Skip to content

Commit

Permalink
feat: #58 #1009 全面适配 docker(实验性)
Browse files Browse the repository at this point in the history
  • Loading branch information
terwer committed Mar 4, 2024
1 parent 94cdb83 commit 901e24f
Show file tree
Hide file tree
Showing 13 changed files with 255 additions and 80 deletions.
76 changes: 59 additions & 17 deletions src/adaptors/api/base/baseBlogApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { PublisherAppInstance } from "~/src/publisherAppInstance.ts"
import { createAppLogger, ILogger } from "~/src/utils/appLogger.ts"
import { useProxy } from "~/src/composables/useProxy.ts"
import { BaseExtendApi } from "~/src/adaptors/base/baseExtendApi.ts"
import { JsonUtil } from "zhi-common"
import { JsonUtil, StrUtil } from "zhi-common"

/**
* 执行代理 fetch 请求
Expand Down Expand Up @@ -62,8 +62,8 @@ export class BaseBlogApi extends BlogApi {
protected appInstance: PublisherAppInstance
protected logger: ILogger
protected cfg: BlogConfig
public readonly proxyFetch: ProxyFetchType
protected readonly baseExtendApi: BaseExtendApi
private readonly proxyFetch: ProxyFetchType

/**
* 初始化API授权适配器
Expand Down Expand Up @@ -108,22 +108,64 @@ export class BaseBlogApi extends BlogApi {
}

// ===================================================================================================================
/**
* API 代理请求
*
* @param url - 请求的 URL
* @param headers - 请求的头部信息,默认为空数组
* @param params - 请求的参数,默认为 undefined
* @param method - 请求的 HTTP 方法,默认为 GET
* @param contentType - 请求的内容类型,默认为 application/json
* @param forceProxy - 是否强制使用代理,默认为 false
*/
public async apiProxyFetch(
url: string,
headers: any[] = [],
params: any = undefined,
method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH" = "GET",
contentType: string = "application/json",
forceProxy: boolean = false
) {
const isCorsProxyAvailable = !StrUtil.isEmptyString(this.cfg.corsAnywhereUrl)
// 如果没有可用的 CORS 代理或者没有强制使用代理,使用默认的自动检测机制
if (!isCorsProxyAvailable || !forceProxy) {
this.logger.info("Using legency api fetch")
return this.proxyFetch(url, headers, params, method, contentType, forceProxy)
} else {
throw new Error("using cors proxy api")
}
}

public async apiFormFetch(url: string, headers: any[], formData: FormData) {
const win = this.appInstance.win
const doFetch = win.require(`${this.appInstance.moduleBase}libs/zhi-formdata-fetch/index.cjs`)

// headers
const header = headers.length > 0 ? headers[0] : {}
this.logger.debug("before zhi-formdata-fetch, headers =>", headers)
this.logger.debug("before zhi-formdata-fetch, url =>", url)

const resText = await doFetch(this.appInstance.moduleBase, url, header, formData)
this.logger.debug("apiForm doFetch success, resText =>", resText)
const resJson = JsonUtil.safeParse<any>(resText, {} as any)
this.logger.debug("apiForm doFetch success, resJson=>", resJson)

return resJson
/**
* API 表单请求
*
* @param url - 请求的 URL
* @param headers - 请求的头部信息,默认为空数组
* @param formData - 表单数据
* @param forceProxy - 是否强制使用代理,默认为 false
*/
public async apiFormFetch(url: string, headers: any[], formData: FormData, forceProxy: boolean = false) {
const isCorsProxyAvailable = !StrUtil.isEmptyString(this.cfg.corsAnywhereUrl)
// 如果没有可用的 CORS 代理或者没有强制使用代理,使用默认的自动检测机制
if (!isCorsProxyAvailable || !forceProxy) {
this.logger.info("Using legency api formFetch")
const win = this.appInstance.win
const doFetch = win.require(`${this.appInstance.moduleBase}libs/zhi-formdata-fetch/index.cjs`)

// headers
const header = headers.length > 0 ? headers[0] : {}
this.logger.debug("before zhi-formdata-fetch, headers =>", headers)
this.logger.debug("before zhi-formdata-fetch, url =>", url)

const resText = await doFetch(this.appInstance.moduleBase, url, header, formData)
this.logger.debug("apiForm doFetch success, resText =>", resText)
const resJson = JsonUtil.safeParse<any>(resText, {} as any)
this.logger.debug("apiForm doFetch success, resJson=>", resJson)

return resJson
} else {
throw new Error("using cors proxy api formFetch")
}
}

// ================
Expand Down
1 change: 1 addition & 0 deletions src/adaptors/api/base/commonBlogConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export class CommonBlogConfig extends BlogConfig {
this.apiUrl = apiUrl
this.username = username
this.password = password
this.tokenSettingUrl = undefined
this.apiStatus = false
this.blogid = ""
this.blogName = ""
Expand Down
28 changes: 14 additions & 14 deletions src/adaptors/api/halo/HaloApiAdaptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,15 +131,15 @@ class HaloApiAdaptor extends BaseBlogApi {
params.post.spec.publishTime = post.dateCreated.toISOString()

// 草稿
const res = await this.haloRequest("/apis/api.console.halo.run/v1alpha1/posts", params, "POST")
const res = await this.haloFetch("/apis/api.console.halo.run/v1alpha1/posts", params, "POST")
this.logger.debug("halo newPost res =>", res)
if (!res?.metadata?.name) {
throw new Error("Halo 文章发布失败")
}
this.logger.debug("halo 文章草稿完成")

// 发布
await this.haloRequest(`/apis/api.console.halo.run/v1alpha1/posts/${params.post.metadata.name}/publish`, {}, "PUT")
await this.haloFetch(`/apis/api.console.halo.run/v1alpha1/posts/${params.post.metadata.name}/publish`, {}, "PUT")
this.logger.debug("halo 文章发布完成")

// 生成文章ID
Expand Down Expand Up @@ -194,11 +194,11 @@ class HaloApiAdaptor extends BaseBlogApi {
params.post.spec.publishTime = post.dateCreated.toISOString()

// 更新文章信息
await this.haloRequest(`/apis/content.halo.run/v1alpha1/posts/${name}`, params.post, "PUT")
await this.haloRequest(`/apis/api.console.halo.run/v1alpha1/posts/${name}/content`, params.content, "PUT")
await this.haloFetch(`/apis/content.halo.run/v1alpha1/posts/${name}`, params.post, "PUT")
await this.haloFetch(`/apis/api.console.halo.run/v1alpha1/posts/${name}/content`, params.content, "PUT")

// 重新发布
await this.haloRequest(
await this.haloFetch(
`/apis/api.console.halo.run/v1alpha1/posts/${params.post.metadata.name}/publish`,
{},
"PUT"
Expand Down Expand Up @@ -246,7 +246,7 @@ class HaloApiAdaptor extends BaseBlogApi {
const haloPostKey = this.getHaloPostidKey(postid)
// const unPublishUrl = `/apis/api.console.halo.run/v1alpha1/posts/${haloPostKey.name}/unpublish`
const recycleUrl = `/apis/api.console.halo.run/v1alpha1/posts/${haloPostKey.name}/recycle`
const res = await this.haloRequest(recycleUrl, {}, "PUT")
const res = await this.haloFetch(recycleUrl, {}, "PUT")
this.logger.debug("halo deletePost res =>", res)

if (!res?.metadata?.name) {
Expand Down Expand Up @@ -351,9 +351,9 @@ class HaloApiAdaptor extends BaseBlogApi {

private async getHaloPost(name: string): Promise<PostRequest | undefined> {
try {
const post = await this.haloRequest(`/apis/content.halo.run/v1alpha1/posts/${name}`, {}, "GET")
const post = await this.haloFetch(`/apis/content.halo.run/v1alpha1/posts/${name}`, {}, "GET")

const content = await this.haloRequest(
const content = await this.haloFetch(
`/apis/api.console.halo.run/v1alpha1/posts/${name}/head-content`,
{},
"GET"
Expand All @@ -378,7 +378,7 @@ class HaloApiAdaptor extends BaseBlogApi {
const newCategories = await Promise.all(
notExistDisplayNames.map(async (name, index) => {
const slug = await AliasTranslator.getPageSlug(name, true)
const category = await this.haloRequest(
const category = await this.haloFetch(
"/apis/content.halo.run/v1alpha1/categories",
{
spec: {
Expand Down Expand Up @@ -412,7 +412,7 @@ class HaloApiAdaptor extends BaseBlogApi {
}

private async getHaloCategories() {
const categories = await this.haloRequest("/apis/content.halo.run/v1alpha1/categories", {}, "GET")
const categories = await this.haloFetch("/apis/content.halo.run/v1alpha1/categories", {}, "GET")
return Promise.resolve(categories.items)
}

Expand All @@ -424,7 +424,7 @@ class HaloApiAdaptor extends BaseBlogApi {
const newTags = await Promise.all(
notExistDisplayNames.map(async (name) => {
const slug = await AliasTranslator.getPageSlug(name, true)
const tag = await this.haloRequest(
const tag = await this.haloFetch(
"/apis/content.halo.run/v1alpha1/tags",
{
spec: {
Expand Down Expand Up @@ -455,7 +455,7 @@ class HaloApiAdaptor extends BaseBlogApi {
}

private async getHaloTags() {
const categories = await this.haloRequest("/apis/content.halo.run/v1alpha1/tags", {}, "GET")
const categories = await this.haloFetch("/apis/content.halo.run/v1alpha1/tags", {}, "GET")
return Promise.resolve(categories.items)
}

Expand All @@ -468,7 +468,7 @@ class HaloApiAdaptor extends BaseBlogApi {
* @param header 请求头
* @private
*/
private async haloRequest(
private async haloFetch(
url: string,
params?: any,
method: "GET" | "POST" | "PUT" | "DELETE" = "POST",
Expand All @@ -489,7 +489,7 @@ class HaloApiAdaptor extends BaseBlogApi {

// 使用兼容的fetch调用并返回统一的JSON数据
const body = ObjectUtil.isEmptyObject(params) ? "" : JSON.stringify(params)
const resJson = await this.proxyFetch(apiUrl, [headers], body, method, contentType)
const resJson = await this.apiProxyFetch(apiUrl, [headers], body, method, contentType)
this.logger.debug("向 Halo 请求数据,resJson =>", resJson)

return resJson ?? null
Expand Down
2 changes: 1 addition & 1 deletion src/adaptors/api/notion/notionApiAdaptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ class NotionApiAdaptor extends BaseBlogApi {

// 使用兼容的fetch调用并返回统一的JSON数据
const body = ObjectUtil.isEmptyObject(params) ? {} : params
const resJson = await this.proxyFetch(apiUrl, [headers], body, method, contentType)
const resJson = await this.apiProxyFetch(apiUrl, [headers], body, method, contentType)
this.logger.debug("向Notion请求数据,resJson =>", resJson)

if (resJson?.status === 400 || resJson?.status === 401 || resJson?.status === 404 || resJson?.status === 429) {
Expand Down
88 changes: 69 additions & 19 deletions src/adaptors/api/telegraph/telegraphApiAdaptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class TelegraphApiAdaptor extends BaseBlogApi {
public async getUsersBlogs(): Promise<UserBlog[]> {
const result: UserBlog[] = []

const checkJson = await this.telegraphRequest("/check", "page_id=0", "POST")
const checkJson = await this.telegraphFetch("/check", "page_id=0", "POST")
if (checkJson.error) {
throw new Error("telegra.ph request error =>" + checkJson.error)
}
Expand All @@ -66,14 +66,15 @@ class TelegraphApiAdaptor extends BaseBlogApi {
return result
}

public async newPost(post: Post, publish?: boolean): Promise<string> {
public async newPost(post: Post, _publish?: boolean): Promise<string> {
const formData = new FormData()
const content = [{ tag: "p", attrs: { dir: "auto" }, children: ["测试正文"] }]
const blobData = new Blob([JSON.stringify(content)], { type: "text/plain" })
formData.append("Data", blobData, "content.html")
formData.append("title", "测试标题")
formData.append("author", this.cfg.username)
formData.append("save_hash", this.cfg.password)
formData.append("page_id", "0")
const blobData = new File(["content"], "content.html", { type: "text/plain" })
formData.append("Data", blobData)

const res = await this.telegraphFormFetch("/save", formData)
if (res.error) {
Expand All @@ -84,7 +85,53 @@ class TelegraphApiAdaptor extends BaseBlogApi {
}
this.logger.debug("telegraph newPost resJson =>", res)

throw new Error("开发中...")
const postMeta = {
page_id: res.page_id,
path: res.path,
}
const postid = JSON.stringify(postMeta)
return postid
}

public async editPost(postid: string, post: Post, publish?: boolean): Promise<boolean> {
const postMeta = JsonUtil.safeParse<any>(postid, {})

const formData = new FormData()
const content = [{ tag: "p", attrs: { dir: "auto" }, children: ["测试正文3"] }]
const blobData = new Blob([JSON.stringify(content)], { type: "text/plain" })
formData.append("Data", blobData, "content.html")
formData.append("title", "测试标题3")
formData.append("author", this.cfg.username)
formData.append("save_hash", this.cfg.password)
formData.append("page_id", postMeta.page_id)

const res = await this.telegraphFormFetch("/save", formData)
if (res.error) {
throw new Error(
"telegra.ph 更新失败,注意:切换设备(包括从PC到浏览器环境)需要重新验证,并且获取新token。详细错误 =>" +
res.error
)
}
this.logger.debug("telegraph editPost resJson =>", res)

return true
}

public async deletePost(postid: string): Promise<boolean> {
throw new Error("telegra.ph 暂不支持删除文章功能")
}

public async getPost(postid: string, useSlug?: boolean): Promise<Post> {
const commonPost = new Post()
commonPost.postid = postid
return commonPost
}

public async getPreviewUrl(postid: string): Promise<string> {
const postMeta = JsonUtil.safeParse<any>(postid, {})
const purl = this.cfg.previewUrl ?? ""
const postUrl = purl.replace("[postid]", postMeta?.path ?? "")
return postUrl
}

// ================
Expand All @@ -93,10 +140,10 @@ class TelegraphApiAdaptor extends BaseBlogApi {
/**
* 向 Telegraph 请求数据
*/
private async telegraphRequest(
private async telegraphFetch(
url: string,
params?: any,
method: "GET" | "POST" | "PUT" | "DELETE" = "POST",
method: "GET" | "POST" | "PUT" | "DELETE" = "GET",
header: Record<any, any> = {}
) {
const contentType = "text/plain"
Expand All @@ -119,7 +166,7 @@ class TelegraphApiAdaptor extends BaseBlogApi {
this.logger.debug("向 Telegraph 请求数据,headers =>", headers)
this.logger.debug("向 Telegraph 请求数据,body =>", body)

const resJson = await this.proxyFetch(apiUrl, [headers], body, method, contentType, true)
const resJson = await this.apiProxyFetch(apiUrl, [headers], body, method, contentType, true)
this.logger.debug("向 Telegraph 请求数据,resJson =>", resJson)

return resJson ?? null
Expand All @@ -129,31 +176,35 @@ class TelegraphApiAdaptor extends BaseBlogApi {
* 向 Telegraph 发送表单数据
*
* @param url 请求地址
* @param formData 表单数据
* @param formData 表单数据,默认为undefined,支持 ReadableStream、Blob | BufferSource | FormData | URLSearchParams | string。这里只需要 FormData
*/
private async telegraphFormFetch(url: string, formData: FormData) {
const apiUrl = `${this.cfg.apiUrl}${url}`
let xCorsHeaders: Record<any, any> = {}

// header

// x-cors-headers
const tphUuidObj = CookieUtils.getCookieObject(this.cfg.corsCookieArray, this.TPH_UUID_KEY)
let header: Record<any, any> = {}
if (!StrUtil.isEmptyString(tphUuidObj[this.TPH_UUID_KEY])) {
header["Cookie"] = `${this.TPH_UUID_KEY}=${tphUuidObj[this.TPH_UUID_KEY]}`
xCorsHeaders["Cookie"] = `${this.TPH_UUID_KEY}=${tphUuidObj[this.TPH_UUID_KEY]}`
}
xCorsHeaders["origin"] = "https://telegra.ph"
xCorsHeaders["referer"] = "https://telegra.ph/"

const headers = {
origin: "https://telegra.ph",
referer: "https://telegra.ph/",
...header,
"x-cors-headers": JSON.stringify(xCorsHeaders),
}
const options: RequestInit = {
method: "POST",
headers: headers,
body: formData,
}

this.logger.debug("向 Telegraph 发送表单数据,apiUrl =>", apiUrl)
this.logger.debug("向 Telegraph 发送表单数据,options =>", options)
const res = await fetch(apiUrl, options)
const resText = await res.text()
this.logger.debug("向 Telegraph 发送表单数据,resText =>", resText)
const resJson = JsonUtil.safeParse<any>(resText, {})

const resJson = await this.apiFormFetch(apiUrl, [headers], formData)
if (resJson.error) {
throw new Error(
"telegra.ph 发布错误,注意:切换设备(包括从PC到浏览器环境)需要重新验证,并且获取新token。详细错误 =>" +
Expand All @@ -162,7 +213,6 @@ class TelegraphApiAdaptor extends BaseBlogApi {
}
this.logger.debug("向 Telegraph 发送表单数据,resJson =>", resJson)

// const resJson = await this.apiFormFetch(apiUrl, [headers], formData)
return resJson
}
}
Expand Down
Loading

0 comments on commit 901e24f

Please sign in to comment.