个人博客传送门:|我是门|
一、Picog开发介绍
Picgo是(作者博客)使用electron-vue
开发的,借用作者的话,“picgo是个上传的流程系统。因此插件其实就是针对这个流程系统的某个部件或者某些部件的开发”。
Picgo的插件开发主要针对五个部分:
-
Transformer
-
Uploader
-
beforeTransformPlugins
-
beforeUploadPlugins
-
afterUploadPlugins
这里我们开发的是上传插件,也就是Uploader。
Picgo调用插件通过调用插件向外暴露的handle方法,同时会向handle传入picgo的ctx,既picgo的上下文对象,包含picgo提供的api。
如下,定义一个register方法,利用ctx的注册方法注册一个uploader插件,同时定义handle和name,picgo调用这个插件时就会调用handle方法。
module.exports = (ctx) => {
const register = () => {
ctx.log.success('百度BOS加载成功')
ctx.helper.uploader.register('baiduBos-uploader', {
handle: handle, //定义插件主方法
config: config,
name: '百度BOS'
})
}
return {
register,
uploader: 'baiduBos-uploader'
}
}
下面是百度云BOS插件的详细开发过程,参考:
二、下载插件模板
Picgo提供插件开发的模板,方便很多,只需要关注具体功能的开发。
流程:
- 首先,全局安装picgo
npm install picgo -g
- picgo安装成功后,在cmd命令行,使用命令创建插件:
picgo init plugin <your-project-name>
因为插件模板是从GitHub下载的,众所周知…卡…慢…崩,所以耐心尝试,或者直接从GitHub网页下载
在下载过程中会提示补充插件的各项信息,如下,这里我选择使用JS开发
[PicGo INFO]: Template files are downloading...
[PicGo SUCCESS]: Template files are downloaded!
# 插件名称
? Plugin name: test
# 插件简介
? Plugin description: 测试
# 作者
? author: <你自己>
# 开发模块(上下键移动,enter选择)
? Choose modules you want to develop: uploader
# 是否只是命令行插件
? Your plugin is just used in CLI? NO
# 用 TypeScript 还是 JavaScript
? Use TS or JS? JS
# 有没有快捷方式
? Your plugin has some shortcut for GUI? NO
# 创建成功
[PicGo SUCCESS]:
Generate template files successfully!
Please cd D:\test, and then
# 接下来进入文件夹 安装依赖包
npm install
# or
yarn
[PicGo SUCCESS]: Done!
![模板2](https://kedaya-blog.fsh.bcebos.com/blogImage/20217/%E6%A8%A1%E6%9D%BF2.jpg)
三、注册插件
下载完插件模板后进入src/index.js
发现是这样式儿的:
module.exports = (ctx) => {
const register = () => {
}
return {
register
}
}
我们需要在register方法中注册我们的插件:
module.exports = (ctx) => {
const register = () => {
ctx.log.success('百度BOS加载成功')
ctx.helper.uploader.register('baiduBos-uploader', {
handle: handle,
config: config,
name: '百度BOS'
})
}
return {
register,
uploader: 'baiduBos-uploader'
}
}
其中handle就是我们插件的主方法,config是用户配置信息。ctx.log.success方法会在日志文件中记录信息,可以作为调试的手段之一,可以在C:\Users\ASUS\AppData\Roaming\picgo\picgo.log
中查看,AppData
是隐藏文件。
四、handle主方法
handle是我们插件运行的主方法,在里面我们需要获取用户配置信息、获取图片的缓存(既ctx.out)、构造请求上传图片、返回图片上传后的URL。
const handle = async (ctx) => {
//获取用户配置信息
const userConfig = ctx.getConfig('picBed.baiduBos-uploader')
if (!userConfig) {
throw new Error('未配置参数,请配置百度BOS上传参数')
}
const bucketName = userConfig.bucketName
const host = userConfig.region
const path = (userConfig.path) ? userConfig.path + '/' : ''
const customUrl = userConfig.customUrl
let dateISO = new Date().toISOString()
//构造ISO标准时间字符串
dateISO = dateISO.slice(0, dateISO.indexOf('.')) + 'Z'
//构造UTC标准时间字符串
const dateUTC = new Date().toUTCString()
try {
//获取图片输出缓存
const imgList = ctx.output
for (let i in imgList) {
//调用generateSignature方法,生成签名
const signature = generateSignature(ctx, userConfig, imgList[i].fileName, dateISO)
let img = imgList[i].buffer
if (!img && imgList[i].base64Image) {
img = Buffer.from(imgList[i].base64Image, 'base64')
}
//调用requestConstruct方法,构造PUT请求
const request = requestConstruct(userConfig, imgList[i].fileName, signature, img, dateUTC,dateISO)
//发起PUT请求
const response = await ctx.Request.request(request)
if (response.statusCode === 200 || response.statusCode === 201) {
delete imgList[i].base64Image
delete imgList[i].buffer
//构造图片URL
const url = (customUrl) ? `${customUrl}/${encodeURI(path)}${encodeURI(imgList[i].fileName)}` : `https://${bucketName}.${host}/${encodeURI(path)}${encodeURI(imgList[i].fileName)}`
imgList[i]['imgUrl'] = url
} else {
throw new Error('Upload failed')
}
}
return ctx
} catch (err) {
if (err.error === 'Upload failed') {
ctx.emit('notification', {
title: '上传失败!',
body: '请检查你的配置项是否正确'
})
} else {
ctx.emit('notification', {
title: '上传失败!',
body: '请检查你的配置项是否正确'
})
}
throw err
}
}
因为函数中有网络请求,所以这里我们使用async关键字。
五、用户配置config方法
config方法返回了一个数组,包含用户需要配置各项信息,具体参考Picgo config方法说明
const config = (ctx) => {
let userConfig = ctx.getConfig('picBed.baiduBos-uploader')
if (!userConfig) {
userConfig = {}
}
const config = [
{
name: 'accessKey',
type: 'input',
default: userConfig.accessKey || '',
message: 'AccessKey不能为空',
required: true
},
{
name: 'secretKey',
type: 'input',
default: userConfig.secretKey || '',
message: 'SecretKey不能为空',
required: true
},
{
name: 'bucketName',
type: 'input',
default: userConfig.bucketName || '',
message: 'BucketName不能为空',
required: true
},
{
name: 'region',
type: 'input',
alias: '地区',
default: userConfig.region || '',
message: '例如:bj.bcebos.com',
required: true
},
{
name: 'path',
type: 'input',
alias: '存储路径',
default: userConfig.path || '',
message: '例如:blog/img',
required: false
},
{
name: 'customUrl',
type: 'input',
alias: '自定义域名',
default: userConfig.customUrl || '',
message: '例如:http://bucket.xxx.com',
required: false
}
]
return config
}
客户端的UI界面会根据config返回的数组显示:
六、生成签名
签名根据百度云签名要求构造,参照百度云IAM签名工具
- 任务一:创建前缀字符串(authStringPrefix)
- 任务二:创建规范请求(canonicalRequest),确定签名头域(signedHeaders)
- 任务三:生成派生签名密钥(signingKey)
- 任务四:生成签名摘要(signature),并拼接最终的认证字符串(authorization)
签名算法是SHA256,这里我们引入crypto库,使用它的sha256签名算法
const crypto_ = require('crypto')
const generateSignature = (ctx, userConfig, fileName, date) => {
const accessKey = userConfig.accessKey
const secretKey = userConfig.secretKey
const bucketName = userConfig.bucketName
const path = (userConfig.path) ? userConfig.path + '/' : ''
//1. 创建规范请求,确定签名头域
const canonicalRequest = `PUT\n/v1/${bucketName}/${encodeURI(path)}${encodeURI(fileName)}\n\nx-bce-date:${encodeURIComponent(date)}`
//2. 创建前缀字符串
const authStringPrefix = `bce-auth-v1/${accessKey}/${date}/1800`
//3. 生成派生签名密钥
const signingKey = crypto_.createHmac('sha256', secretKey).update(authStringPrefix).digest('hex')
//4. 生成签名摘要
const signature = crypto_.createHmac('sha256', signingKey).update(canonicalRequest).digest('hex')
//5. 拼接最终的认证字符串
const authorization = `bce-auth-v1/${accessKey}/${date}/1800/x-bce-date/${signature}`
return authorization
}
七、构造请求
构造上传图片请求,参照百度云PutObject接口
返回ctx.Request.request方法接受的请求参数
const requestConstruct= (userConfig, fileName, signature, img, dateUTC, dateISO) => {
const bucketName = userConfig.bucketName
const host = userConfig.region
const path = (userConfig.path) ? userConfig.path + '/' : ''
return {
method: 'PUT',
uri: `http://${host}/v1/${bucketName}/${encodeURI(path)}${encodeURI(fileName)}`,
headers: {
Authorization: signature,
Date: dateUTC,
'x-bce-date': dateISO
},
body: img,
resolveWithFullResponse: true
}
}
八、插件安装
插件开发完毕后,将插件文件夹picgo-plugin-<your-plugin-name>
复制到picgo配置文件夹C:\Users\ASUS\AppData\Roaming\picgo
下
在cmd进入C:\Users\ASUS\AppData\Roaming\picgo
执行下列命令就可以安装
npm install ./picgo-plugin-<your-plugin-name>
注意插件文件夹名字必须以picgo-plugin-作为前缀,否则安装的时候picgo将不会读取。
具体参照Picgo插件测试
安装成功后重启Picgo:
完整项目地址:https://github.com/Yangbin-v/picgo-plugin-baiduBos-uploader