appCefScheme.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. package main
  2. import (
  3. "net/url"
  4. "os"
  5. "path/filepath"
  6. "strings"
  7. "unsafe"
  8. "github.com/energye/energy/v2/cef"
  9. )
  10. func RegSchema(browser *cef.ICefBrowser) {
  11. // 创建 SchemeHandlerFactory
  12. factory := cef.SchemeHandlerFactoryRef.New()
  13. // 创建SchemeHandlerFactory的回调函数
  14. factory.SetNew(func(browser *cef.ICefBrowser, frame *cef.ICefFrame, schemeName string, request *cef.ICefRequest) *cef.ICefResourceHandler {
  15. handler := cef.ResourceHandlerRef.New(browser, frame, schemeName, request)
  16. var (
  17. // 预设一些变量
  18. fileBytes []byte
  19. fileBytesReadPosition = 0
  20. err error
  21. status int32 = 0
  22. statusText = ""
  23. mimeType = ""
  24. )
  25. // 当加载指定的 scheme 后, 回调以下函数, 按step
  26. // step 1, ProcessRequest , 处理请求, 在这里预先加载需要的资源和 step 2 需要的响应状态
  27. handler.ProcessRequest(func(request *cef.ICefRequest, callback *cef.ICefCallback) bool {
  28. urlFile := request.URL()
  29. // 默认404
  30. status = 404
  31. statusText = "ERROR"
  32. mimeType = ""
  33. // 请求地址是我们预告定义好的地址
  34. i := strings.Index(urlFile, "file")
  35. if i == 0 {
  36. fpath := strings.TrimLeft(urlFile, "file:///")
  37. fpath, err = url.QueryUnescape(fpath)
  38. if err != nil {
  39. fileBytes = nil
  40. return false
  41. }
  42. fpath = strings.Split(fpath, "?")[0]
  43. fileBytes, err = os.ReadFile(fpath)
  44. if err != nil {
  45. println("ProcessRequest url:", fpath, err.Error())
  46. fileBytes = nil
  47. return false
  48. }
  49. println("ProcessRequest url ok:", fpath)
  50. fileBytesReadPosition = 0 //每次都将读取位置归0
  51. // 加载资源成功后设置成功响应状态
  52. status = 200
  53. statusText = "OK"
  54. ext := strings.TrimLeft(filepath.Ext(fpath), ".")
  55. mimeType = cef.GetMimeType(ext) // get html MimeType
  56. callback.Cont() // 继续
  57. return true
  58. } else {
  59. // 返回 false 后不会执行 ReadResponse 回调函数
  60. fileBytes = nil
  61. return false
  62. }
  63. })
  64. // step 2, 响应处理器, 将 step 1 的处理结果返回
  65. handler.GetResponseHeaders(func(response *cef.ICefResponse) (responseLength int64, redirectUrl string) {
  66. if fileBytes != nil {
  67. response.SetStatus(status)
  68. response.SetStatusText(statusText)
  69. response.SetMimeType(mimeType)
  70. responseLength = int64(len(fileBytes))
  71. }
  72. return
  73. })
  74. // step3, 读取响应内容
  75. handler.ReadResponse(func(dataOut uintptr, bytesToRead int32, callback *cef.ICefCallback) (bytesRead int32, result bool) {
  76. // 这个函数可能会被多次调用, 如果响应流大于 bytesToRead 时
  77. // 我们是按块读取 每个块最大bytesToRead且小于实际的要响应的流字节数
  78. // 从最新的读取位置fileBytesReadPosition把流返回到 dataOut
  79. if fileBytes != nil && len(fileBytes) > 0 {
  80. var i int32 = 0 // 默认 0
  81. // 循环读取字节流内容
  82. for i < bytesToRead && fileBytesReadPosition < len(fileBytes) {
  83. // 这里是通过指针地址将赋值, []byte 缓存数组
  84. // 描述: dataOut byte[i] = fileBytes byte[fileBytesReadPosition]
  85. *(*byte)(unsafe.Pointer(dataOut + uintptr(i))) = fileBytes[fileBytesReadPosition]
  86. fileBytesReadPosition++ // 缓存数据的下一个位置, 如果 len(fileBytes) 大于 bytesToRead 时
  87. i++ // 计数, 当前最后的输出大小
  88. }
  89. // i当前读取的字节数
  90. return i, i > 0
  91. }
  92. return
  93. })
  94. return handler
  95. })
  96. requestContext := browser.GetRequestContext()
  97. requestContext.RegisterSchemeHandlerFactory("file", "", factory)
  98. }