基于Webhook的代码仓库事件监听与通知系统设计与实现

news2026/5/3 18:22:18
1. 项目概述一个为开发者量身打造的代码通知管家如果你和我一样每天需要同时盯着好几个代码仓库的动态无论是自己负责的项目还是团队协作的公共库那么你一定经历过这种场景某个关键分支被推送了你错过了一个重要的Pull Request被合并了你事后才知道或者一个依赖库发布了安全更新你没能第一时间响应。在快节奏的开发工作中信息滞后往往意味着风险的累积和效率的降低。mylee04/code-notify这个项目就是为了解决这个痛点而生的。它本质上是一个高度可定制、轻量级的代码仓库事件监听与通知转发器。你可以把它想象成一个24小时待命的“代码哨兵”它静静地守在你的GitHub、GitLab等代码托管平台旁边一旦发生你关心的任何事件——比如新的提交、合并请求、Issue创建、版本发布——它就会立刻行动起来通过你预设的渠道比如钉钉、飞书、企业微信、Slack甚至是邮件或Webhook将消息精准地推送到你的面前。这个工具的核心价值在于“主动”和“聚合”。它把原本需要你被动去刷新页面、查看邮件才能获取的分散信息变成了主动、实时、集中推送的提醒。对于个人开发者它是提升效率、避免遗漏的利器对于团队它则是构建自动化协同流程、确保信息同步的基础组件。接下来我将带你深入拆解这个项目的设计思路、实现细节并分享如何从零开始部署和定制属于你自己的“代码通知管家”。2. 核心架构与设计思路拆解2.1 事件驱动与Webhook机制解析code-notify的核心工作原理建立在现代代码托管平台普遍支持的Webhook机制之上。理解这一点是理解整个项目的基础。Webhook通俗讲就是一种“反向API”或“HTTP回调”。通常我们调用API是主动去服务器“拉取”数据而Webhook是我们在服务器上注册一个URL即我们的code-notify服务地址当特定事件如push,pull_request发生时平台会主动向这个URL“推送”一个包含事件详情的HTTP POST请求。code-notify扮演的角色就是这个URL背后的服务端。它的架构是典型的事件驱动型监听层一个HTTP服务器通常基于Express.js、Koa等Node.js框架持续监听来自GitHub/GitLab等平台的Webhook POST请求。解析与过滤层收到请求后首先验证请求签名防止伪造然后解析JSON格式的载荷Payload。这一层会根据配置文件判断当前事件类型event_type、仓库repository、分支branch等是否匹配用户设定的关注规则。转换与路由层对于匹配的事件将其包含的信息如提交者、提交信息、差异链接、PR标题等从平台原始的、复杂的JSON格式提取并转换成更适合阅读的、结构化的消息模板。通知发送层将格式化好的消息通过对应的客户端SDK或API发送到目标通知渠道如钉钉机器人、飞书群聊等。这种设计的优势在于解耦和可扩展性。监听层与具体平台耦合但通知层完全独立。这意味着未来要支持新的代码平台如Gitee、Bitbucket只需增加对应的Webhook解析器要支持新的通知方式如短信、电话也只需实现新的发送器Sender。2.2 配置驱动与规则引擎设计一个通知系统如果对所有事件都一视同仁地发送提醒很快就会变成“狼来了”导致重要的消息被淹没在噪音中。因此code-notify的精髓在于其配置驱动的规则引擎。在它的配置文件通常是config.yaml或config.json中你可以定义非常精细的规则。一个典型的规则可能长这样rules: - name: 主分支推送告警 repository: my-org/production-api events: [push] branch: main actions: [opened, synchronize] # 对于PR事件可以更细粒度 notify_to: dingtalk_critical_channel template: critical_push.md # 使用一个更醒目的消息模板 - name: 团队仓库PR通知 repository: my-org/* # 支持通配符 events: [pull_request] notify_to: feishu_team_group condition: payload.pull_request.requested_reviewers.length 0 # 甚至支持JS表达式条件这个规则引擎的设计考量包括优先级匹配规则按顺序匹配第一条匹配的规则生效这允许你设置“兜底规则”和“特例规则”。条件表达式高级实现可以支持类似Javascript的条件判断让你能基于payload的任意字段进行过滤例如“仅当PR被标记为draft时不通知”。模板化消息内容与规则分离。你可以为不同的事件、不同的紧急程度准备不同的Markdown或文本模板保持通知内容的整洁和一致。注意规则的设计是门艺术。一开始建议从“宽”开始先接收所有重要事件然后根据一段时间的通知记录逐步收紧规则过滤掉那些你实际不关心的“噪音”找到通知效率与信息价值的平衡点。2.3 高可用与可维护性考量虽然code-notify本身不直接处理核心业务逻辑但作为信息管道其稳定性和可维护性至关重要。无状态设计服务本身不存储事件数据日志除外每次Webhook处理都是独立的。这使得它可以轻松水平扩展只需部署多个实例并用负载均衡器如Nginx将Webhook请求分发即可。队列缓冲在高并发场景下例如大型开源项目瞬间收到大量PR事件直接同步处理Webhook并发送通知可能导致响应超时或通知丢失。一个更健壮的方案是引入一个消息队列如Redis、RabbitMQ。Webhook处理器只负责验证和投递事件到队列然后由独立的消费者 worker 进程从队列中取出事件执行解析、过滤和发送。这实现了异步解耦和流量削峰。完备的日志与监控必须记录所有入站Webhook至少记录事件类型和仓库以及所有发出的通知包括成功或失败。这不仅是排查问题的依据比如为什么没收到某个PR的通知也是优化规则的数据基础。同时需要监控服务的健康状态如HTTP服务器是否存活、队列积压情况、各通知渠道的API调用成功率等。配置热更新理想情况下修改规则配置文件后无需重启服务就能生效。这可以通过监听配置文件变化或提供一个管理API来实现。3. 核心模块实现与实操要点3.1 Webhook服务器的安全实现接收公网Webhook安全是第一道防线。主要风险是伪造请求恶意触发你的通知和重复攻击。1. 签名验证以GitHub为例GitHub在发送Webhook时会在请求头X-Hub-Signature-256中包含一个基于你设置的secret和请求体计算出的SHA256 HMAC签名。服务器端必须进行验证。const crypto require(crypto); const express require(express); const app express(); const GITHUB_SECRET process.env.WEBHOOK_SECRET; app.post(/webhook/github, express.json({ verify: (req, res, buf) { req.rawBody buf.toString(); // 保存原始body用于验签 } }), (req, res) { const signature req.headers[x-hub-signature-256]; if (!signature) { return res.status(401).send(No signature); } const expectedSignature sha256 crypto .createHmac(sha256, GITHUB_SECRET) .update(req.rawBody) .digest(hex); if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) { return res.status(401).send(Invalid signature); } // 签名验证通过处理事件... res.status(200).send(OK); });实操心得secret务必使用强随机字符串并通过环境变量传入绝对不要硬编码在代码中。GitLab的签名头是X-GitLab-Token原理是简单的Token比对同样需要妥善保管Token。2. 防重放攻击可选但推荐理论上攻击者截获一个合法的Webhook请求后可以重复发送。可以通过检查X-GitHub-Delivery这个唯一ID是否已被处理过来防范。简单的实现可以用一个内存Set或Redis暂存最近一段时间如5分钟的所有ID并进行检查。3.2 多通知渠道适配器模式为了支持钉钉、飞书、企业微信等多种渠道最佳实践是使用适配器模式。定义一个统一的Notifier接口所有渠道适配器都实现这个接口。// 统一的发送器接口 class Notifier { async send(message) { throw new Error(send() must be implemented); } } // 钉钉机器人适配器 class DingTalkNotifier extends Notifier { constructor(webhookUrl, secret) { super(); this.webhookUrl webhookUrl; this.secret secret; } async send(message) { // 1. 根据secret计算签名钉钉机器人安全设置 const timestamp Date.now(); const stringToSign ${timestamp}\n${this.secret}; const sign crypto.createHmac(sha256, this.secret) .update(stringToSign) .digest(base64); // 2. 构造钉钉要求的消息格式 const data { msgtype: markdown, markdown: { title: message.title, text: message.content }, at: { atMobiles: message.atMobiles || [], isAtAll: message.isAtAll || false } }; // 3. 发送HTTP请求 const url ${this.webhookUrl}timestamp${timestamp}sign${encodeURIComponent(sign)}; const resp await axios.post(url, data); if (resp.data.errcode ! 0) { throw new Error(DingTalk send failed: ${resp.data.errmsg}); } } } // 飞书、企业微信等适配器类似...这样在规则引擎中notify_to: dingtalk_critical就对应到初始化好的DingTalkNotifier实例。增加新渠道只需新增一个适配器类并在配置中引用即可核心逻辑无需改动。3.3 消息模板引擎与内容渲染原始Webhook的JSON数据非常冗长直接发送可读性极差。我们需要一个模板引擎来提取关键信息并格式化成友好的消息。1. 模板设计推荐使用类似Handlebars或EJS的模板语言它们逻辑简单足以满足需求。模板文件可以存放在templates/目录下。例如一个push.md.hbs模板** 代码推送通知** - **仓库**: {{repository.full_name}} - **分支**: {{ref}} ({{compare}}) - **提交者**: {{pusher.name}} - **最新提交**: {{head_commit.message}} - **查看详情**: {{head_commit.url}}2. 数据转换与渲染Webhook来自不同平台数据结构差异很大。我们需要一个“标准化”层将GitHub的push事件、GitLab的Push Hook事件转换成统一的、供模板使用的上下文对象。class PayloadTransformer { transformGithubPush(payload) { return { event: push, repository: { full_name: payload.repository.full_name, url: payload.repository.html_url }, ref: payload.ref.replace(refs/heads/, ), // 提取分支名 compare: payload.compare, pusher: payload.pusher, head_commit: { message: payload.head_commit.message, url: payload.head_commit.url } // ... 其他字段 }; } transformGitlabPush(payload) { // 类似地处理GitLab数据结构 return { event: push, repository: { full_name: payload.project.path_with_namespace, url: payload.project.web_url }, ref: payload.ref, // GitLab没有直接的compare链接需要拼接 compare: ${payload.project.web_url}/compare/${payload.before.slice(0,8)}...${payload.after.slice(0,8)}, pusher: { name: payload.user_name }, head_commit: { message: payload.commits?.[0]?.message || No commit message, url: ${payload.project.web_url}/commit/${payload.after} } }; } }渲染时只需调用对应的转换器然后将结果对象注入模板引擎即可生成最终消息文本。4. 从零部署与配置实战4.1 环境准备与项目初始化假设我们使用Node.js环境。首先确保系统已安装Node.js建议LTS版本和npm。# 1. 克隆项目这里以假设的目录结构为例 git clone repository-url code-notify cd code-notify # 2. 安装依赖 npm install # 3. 复制配置文件样例并修改 cp config.example.yaml config.yaml cp .env.example .env关键依赖分析express: Web框架用于提供Webhook端点。axios: 用于向各通知渠道API发送HTTP请求。yaml或js-yaml: 用于解析YAML格式的配置文件。handlebars: 模板引擎。winston或pino: 结构化日志记录。dotenv: 从.env文件加载环境变量。4.2 详细配置解析与示例让我们深入一个完整的config.yaml示例# config.yaml server: port: 3000 path: /webhook # Webhook接收的路径 host: 0.0.0.0 # 各通知渠道的配置 notifiers: dingtalk_team: type: dingtalk webhook_url: ${DINGTALK_WEBHOOK} # 从环境变量读取 secret: ${DINGTALK_SECRET} # 可以配置代理如果需要 # proxy: http://your-proxy:port feishu_release: type: feishu webhook_url: ${FEISHU_WEBHOOK_RELEASE} # 飞书支持签名校验 secret: ${FEISHU_SECRET_RELEASE} wecom_alert: type: wecom webhook_url: ${WECOM_WEBHOOK_ALERT} # 规则定义顺序重要 rules: - name: 生产库主干推送高优 # 匹配特定仓库的main/master分支推送 repository: my-company/production-service events: [push] branch: [main, master] # 通知到钉钉团队群并所有人 notify_to: dingtalk_team template: push_critical.md extra: at_all: true - name: 所有仓库的PR创建与合并 repository: my-company/* # 通配符匹配所有仓库 events: [pull_request] # 只关注opened新建, closed关闭/合并事件 actions: [opened, closed] # 如果是合并merged的关闭才通知飞书发布群 condition: payload.actionclosed payload.pull_request.mergedtrue ? feishu_release : dingtalk_team template: pull_request.md - name: Issue创建与评论 repository: my-company/* events: [issues, issue_comment] notify_to: dingtalk_team template: issue.md - name: 兜底规则记录日志 repository: * events: [*] notify_to: logger # 可以定义一个只写日志的Notifier template: generic.md对应的.env文件# .env WEBHOOK_SECRETyour_github_webhook_secret_here DINGTALK_WEBHOOKhttps://oapi.dingtalk.com/robot/send?access_tokenxxx DINGTALK_SECRETyour_dingtalk_secret_here FEISHU_WEBHOOK_RELEASEhttps://open.feishu.cn/open-apis/bot/v2/hook/xxx FEISHU_SECRET_RELEASEyour_feishu_secret_here WECOM_WEBHOOK_ALERThttps://qyapi.weixin.qq.com/cgi-bin/webhook/send?keyxxx4.3 服务部署与反向代理配置在本地开发测试后需要部署到公网服务器以便GitHub等平台能够访问你的Webhook端点。1. 使用PM2进行进程管理PM2可以保证服务在后台稳定运行并在崩溃后自动重启。# 全局安装PM2 npm install -g pm2 # 使用PM2启动服务并设置环境变量 NODE_ENVproduction WEBHOOK_SECRETxxx pm2 start app.js --name code-notify # 设置开机自启 pm2 startup pm2 save2. 配置Nginx反向代理强烈推荐不建议直接将Node.js服务暴露在公网80/443端口。使用Nginx作为反向代理可以处理SSL、负载均衡、静态文件等更安全高效。# /etc/nginx/sites-available/code-notify server { listen 80; server_name your-domain.com; # 你的域名 # 重定向HTTP到HTTPS return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; server_name your-domain.com; ssl_certificate /path/to/your/fullchain.pem; ssl_certificate_key /path/to/your/privkey.pem; # 其他SSL优化配置... location /webhook { # 对应config.yaml中的server.path proxy_pass http://localhost:3000; # 转发到本地的Node.js服务 proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 重要确保Nginx将原始请求体传递给后端用于签名验证 proxy_set_header X-Original-Body $request_body; # 或者更可靠的方式是让后端直接从 socket 读取但需要后端配合。 # 通常只要确保Nginx不修改body且后端使用express.raw()或req.rawBody即可。 client_max_body_size 10M; # GitHub Webhook可能较大 } # 可以添加一个健康检查端点 location /health { proxy_pass http://localhost:3000/health; access_log off; } }配置后你的Webhook完整地址就是https://your-domain.com/webhook。3. 在GitHub上配置Webhook进入你的仓库Settings-Webhooks-Add webhook。Payload URL: 填写https://your-domain.com/webhook/github(根据你的实际路由)Content type: 选择application/jsonSecret: 填写你在.env中设置的WEBHOOK_SECRETWhich events...: 选择Let me select individual events.然后勾选你关心的事件如Push,Pull requests,Issues等。点击Add webhook。GitHub会发送一个ping事件进行测试你可以在服务日志和GitHub的WebhookRecent Deliveries中查看是否成功。5. 高级功能与定制化扩展5.1 实现条件过滤与自定义脚本基础的仓库、分支、事件类型过滤可能不够用。我们可以通过condition字段支持更复杂的逻辑。一种实现方式是嵌入一个安全的JavaScript表达式求值器如vm2或eval在严格受控环境下。rules: - name: 仅通知涉及特定文件修改的PR repository: my-org/config-repo events: [pull_request] condition: | payload.action opened payload.pull_request.changed_files 5 payload.pull_request.files.some(f f.filename.includes(package.json)) notify_to: feishu_team更强大的扩展是支持自定义脚本处理器。在规则配置中指定一个脚本文件当事件匹配时执行该脚本。脚本可以访问完整的payload并返回一个布尔值决定是否触发通知甚至可以动态修改要发送的消息内容。// scripts/check_pr_size.js module.exports function(payload, context) { // 检查PR的增减行数超过1000行则认为是大型PR发送到特定频道 const additions payload.pull_request.additions; const deletions payload.pull_request.deletions; if (additions deletions 1000) { context.notify_to dingtalk_large_pr_channel; // 动态修改通知目标 return true; } return false; // 不触发通知 };5.2 构建管理面板与状态监控对于团队使用一个简单的管理面板非常有用。可以创建一个简单的HTTP管理端点需认证用于查看当前配置和规则。动态启用/禁用规则无需重启服务。查看最近的处理日志和错误。手动重试失败的通知。使用Express可以快速搭建// admin.js const express require(express); const basicAuth require(express-basic-auth); const app express(); app.use(basicAuth({ users: { [process.env.ADMIN_USER]: process.env.ADMIN_PASS }, challenge: true })); app.get(/admin/rules, (req, res) { res.json(loadRules()); // 返回当前规则 }); app.post(/admin/rules/:id/toggle, (req, res) { // 切换某条规则的启用状态 // 实现逻辑... }); app.get(/admin/logs, (req, res) { // 返回最近的日志可以分页 // 实现逻辑... });同时集成健康检查端点/health返回服务状态、各渠道连接状态等便于纳入统一的监控系统如Prometheus Grafana。5.3 与其他自动化工具集成code-notify可以成为你自动化工作流的“触发器”或“最后一公里”。与CI/CD集成当收到push到特定分支的事件时不仅可以发通知还可以通过调用Jenkins、GitLab CI或GitHub Actions的API来触发构建流水线。与项目管理工具联动当收到issues事件时除了发通知还可以同步信息到Jira、Trello等工具。作为更复杂Bot的一部分你可以扩展它使其能够响应评论中的特定命令。例如在PR评论中回复“/deploy staging”Bot识别后触发部署流程并将结果通过通知反馈回来。这需要解析issue_comment事件的payload.comment.body。6. 故障排查与性能优化实录6.1 常见问题与解决方案速查表在实际运行中你可能会遇到以下问题问题现象可能原因排查步骤与解决方案收不到任何通知1. Webhook未成功送达2. 规则未匹配3. 通知发送失败1.检查服务日志看是否有/webhook的访问记录。检查Nginx/Access Log。2.检查GitHub Webhook后台查看Recent Deliveries红色表示失败点击查看响应和请求详情。3.检查规则确认事件类型、仓库名、分支名是否完全匹配注意大小写。4.检查通知渠道配置机器人Webhook URL和Secret是否正确是否已开启。手动用curl测试机器人是否可用。收到重复通知1. Webhook被重复发送平台重试2. 规则匹配了多条1. 这是正常现象平台可能因未收到2xx响应而重试。确保你的服务在处理成功后总是返回200 OK。2. 检查规则顺序和条件确保一个事件只被一条规则捕获。可以使用condition进行更精确的过滤。通知内容格式错乱1. 模板语法错误2. 数据转换出错字段为空1.检查模板文件确保{{}}等语法正确闭合。2.在日志中打印出转换后的上下文对象对比不同平台GitHub/GitLab的payload结构差异调整PayloadTransformer。服务响应慢或超时1. 网络问题如通知渠道API慢2. 同步处理耗时操作1.为HTTP请求设置合理的超时时间如5秒。2.引入消息队列将耗时的处理和发送任务异步化Webhook处理器快速响应202 Accepted。签名验证失败1. Secret配置不一致2. 请求体被修改1.核对环境变量、配置文件、平台Webhook设置中的Secret是否完全一致。2.检查Nginx配置确保没有修改请求体。在后端打印原始请求体字符串与平台发送的进行比对。内存使用持续增长内存泄漏1.检查日志记录是否将大量数据如完整payload无限期保存在内存中。2.使用Node.js内存分析工具如heapdump,clinic.js定位泄漏点。3.确保HTTP客户端如axios的响应流被正确消费和销毁。6.2 性能优化与稳定性实践1. 引入消息队列以Bull Redis为例这是提升稳定性的关键一步。// producer.js (Webhook处理器) const Queue require(bull); const webhookQueue new Queue(webhooks, redis://127.0.0.1:6379); app.post(/webhook/github, async (req, res) { // 1. 签名验证... // 2. 将任务加入队列立即返回202 await webhookQueue.add({ event: req.headers[x-github-event], payload: req.body, deliveryId: req.headers[x-github-delivery] }); res.status(202).send(Accepted); // 立即响应避免超时 }); // consumer.js (Worker进程) const Queue require(bull); const webhookQueue new Queue(webhooks, redis://127.0.0.1:6379); webhookQueue.process(async (job) { const { event, payload, deliveryId } job.data; // 在这里执行耗时的规则匹配、消息渲染、发送通知等逻辑 // 即使处理失败Bull也会自动重试可配置 });2. 实现通知失败重试与降级网络波动或渠道API临时不可用可能导致发送失败。必须实现重试机制。指数退避重试第一次失败后等待1秒重试第二次失败后等待2秒第三次4秒以此类推。失败降级当向主渠道如钉钉发送多次失败后可以降级到备用渠道如邮件或另一个群组。持久化失败任务将最终失败的任务信息事件ID、错误原因记录到数据库或文件便于后续人工排查和补偿。3. 日志分级与集中管理使用winston或pino配置不同级别的日志error,warn,info,debug。info级别记录每个Webhook的接收和通知发送成功。warn级别记录规则匹配失败、渠道API返回非致命错误。error级别记录签名验证失败、程序异常、多次重试后仍失败。 将日志输出到文件并配合logrotate进行管理。对于分布式部署可以考虑将日志发送到ELK或Loki等集中式日志系统。4. 配置热重载实现一个SIGHUP信号处理器或一个HTTP端点当接收到信号时重新读取配置文件并更新内存中的规则而无需重启服务避免通知中断。let currentConfig loadConfig(); process.on(SIGHUP, () { console.log(Reloading configuration...); try { currentConfig loadConfig(); // 重新初始化Notifiers等 } catch (err) { console.error(Failed to reload config:, err); } });经过以上从架构设计到实战部署再到高级优化和问题排查的完整拆解一个健壮、灵活、实用的code-notify系统就已经构建完成了。它的价值会随着你规则的精雕细琢而日益凸显最终成为你开发流程中一个无声却不可或缺的高效伙伴。记住好的工具不是增加负担而是让你更专注于创造。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2575203.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…