This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
Doric/doric-web/src/DoricDriver.ts

165 lines
5.9 KiB
TypeScript
Raw Normal View History

2021-09-16 12:52:02 +08:00
import { jsCallResolve, jsCallReject, jsCallbackTimer, jsReleaseContext, jsHookAfterNativeCall } from 'doric/src/runtime/sandbox'
2019-12-19 11:52:15 +08:00
import { acquireJSBundle, acquirePlugin } from './DoricRegistry'
2019-12-19 12:45:40 +08:00
import { getDoricContext } from './DoricContext'
import { DoricPlugin } from './DoricPlugin'
2019-12-19 11:52:15 +08:00
2019-12-26 17:33:22 +08:00
function getScriptId(contextId: string) {
return `__doric_script_${contextId}`
2019-12-19 11:52:15 +08:00
}
2019-12-21 12:14:38 +08:00
const originSetTimeout = window.setTimeout
const originClearTimeout = window.clearTimeout
const originSetInterval = window.setInterval
const originClearInterval = window.clearInterval
2019-12-19 11:52:15 +08:00
2019-12-21 12:14:38 +08:00
const timers: Map<number, { handleId: number, repeat: boolean }> = new Map
2019-12-19 11:52:15 +08:00
export function injectGlobalObject(name: string, value: any) {
Reflect.set(window, name, value, window)
}
2019-12-26 17:33:22 +08:00
export function loadJS(contextId: string, script: string) {
2019-12-19 11:52:15 +08:00
const scriptElement = document.createElement('script')
scriptElement.text = script
2019-12-26 17:33:22 +08:00
scriptElement.id = getScriptId(contextId)
2019-12-19 11:52:15 +08:00
document.body.appendChild(scriptElement)
}
function packageModuleScript(name: string, content: string) {
2019-12-21 12:14:38 +08:00
return `Reflect.apply(doric.jsRegisterModule,this,[${name},Reflect.apply(function(__module){(function(module,exports,require,setTimeout,setInterval,clearTimeout,clearInterval){
2019-12-19 11:52:15 +08:00
${content}
2019-12-21 12:14:38 +08:00
})(__module,__module.exports,doric.__require__,doricSetTimeout,doricSetInterval,doricClearTimeout,doricClearInterval);
2019-12-19 11:52:15 +08:00
return __module.exports;},this,[{exports:{}}])])`
}
function packageCreateContext(contextId: string, content: string) {
return `//@ sourceURL=contextId_${contextId}.js
Reflect.apply(function(doric,context,Entry,require,exports,setTimeout,setInterval,clearTimeout,clearInterval){
2019-12-19 11:52:15 +08:00
${content}
},undefined,[undefined,doric.jsObtainContext("${contextId}"),doric.jsObtainEntry("${contextId}"),doric.__require__,{},doricSetTimeout,doricSetInterval,doricClearTimeout,doricClearInterval])`
2019-12-19 11:52:15 +08:00
}
function initDoric() {
2019-12-25 15:19:41 +08:00
injectGlobalObject("Environment", {
platform: "web"
2019-12-25 15:19:41 +08:00
})
2019-12-19 11:52:15 +08:00
injectGlobalObject('nativeLog', (type: 'd' | 'w' | 'e', message: string) => {
switch (type) {
case 'd':
console.log(message)
break
case 'w':
console.warn(message)
break
case 'e':
console.error(message)
break
}
})
injectGlobalObject('nativeRequire', (moduleName: string) => {
const bundle = acquireJSBundle(moduleName)
if (bundle === undefined || bundle.length === 0) {
console.log(`Cannot require JS Bundle :${moduleName}`)
return false
} else {
2021-03-02 10:28:33 +08:00
loadJS(moduleName, packageModuleScript(moduleName, bundle))
2019-12-19 11:52:15 +08:00
return true
}
})
2019-12-19 12:45:40 +08:00
injectGlobalObject('nativeBridge', (contextId: string, namespace: string, method: string, callbackId: string, args?: any) => {
2019-12-19 11:52:15 +08:00
const pluginClass = acquirePlugin(namespace)
2019-12-19 12:45:40 +08:00
const doricContext = getDoricContext(contextId)
if (pluginClass === undefined) {
console.error(`Cannot find Plugin:${namespace}`)
return false
}
if (doricContext === undefined) {
console.error(`Cannot find Doric Context:${contextId}`)
return false
}
let plugin = doricContext.pluginInstances.get(namespace)
if (plugin === undefined) {
plugin = new pluginClass(doricContext) as DoricPlugin
doricContext.pluginInstances.set(namespace, plugin)
}
if (!Reflect.has(plugin, method)) {
console.error(`Cannot find Method:${method} in plugin ${namespace}`)
return false
}
const pluginMethod = Reflect.get(plugin, method, plugin)
if (typeof pluginMethod !== 'function') {
console.error(`Plugin ${namespace}'s property ${method}'s type is ${typeof pluginMethod} not function,`)
}
const ret = Reflect.apply(pluginMethod, plugin, [args])
if (ret instanceof Promise) {
ret.then(
e => {
jsCallResolve(contextId, callbackId, e)
2021-09-16 12:52:02 +08:00
markNeedHook()
2019-12-19 12:45:40 +08:00
},
e => {
jsCallReject(contextId, callbackId, e)
2021-09-16 12:52:02 +08:00
markNeedHook()
2019-12-19 12:45:40 +08:00
})
2019-12-19 13:34:56 +08:00
} else if (ret !== undefined) {
2021-04-30 16:47:11 +08:00
Promise.resolve(ret).then((ret) => {
jsCallResolve(contextId, callbackId, ret)
2021-09-16 12:52:02 +08:00
markNeedHook()
2021-04-30 16:47:11 +08:00
})
2019-12-19 12:45:40 +08:00
}
2019-12-19 11:52:15 +08:00
return true
})
2019-12-21 12:14:38 +08:00
injectGlobalObject('nativeSetTimer', (timerId: number, time: number, repeat: boolean) => {
if (repeat) {
const handleId = originSetInterval(() => {
jsCallbackTimer(timerId)
2021-09-16 12:52:02 +08:00
markNeedHook()
2019-12-21 12:14:38 +08:00
}, time)
timers.set(timerId, { handleId, repeat })
} else {
const handleId = originSetTimeout(() => {
jsCallbackTimer(timerId)
2021-09-16 12:52:02 +08:00
markNeedHook()
2019-12-21 12:14:38 +08:00
}, time)
timers.set(timerId, { handleId, repeat })
}
})
injectGlobalObject('nativeClearTimer', (timerId: number) => {
const timerInfo = timers.get(timerId)
if (timerInfo) {
if (timerInfo.repeat) {
originClearInterval(timerInfo.handleId)
} else {
originClearTimeout(timerInfo.handleId)
}
}
})
2019-12-19 11:52:15 +08:00
}
2019-12-21 12:14:38 +08:00
2019-12-19 13:07:33 +08:00
export function createContext(contextId: string, content: string) {
2019-12-26 17:33:22 +08:00
loadJS(contextId, packageCreateContext(contextId, content))
}
export function destroyContext(contextId: string) {
jsReleaseContext(contextId)
const scriptElement = document.getElementById(getScriptId(contextId))
if (scriptElement) {
document.body.removeChild(scriptElement)
}
2019-12-19 13:07:33 +08:00
}
2021-09-16 12:52:02 +08:00
let requesting = false
export function markNeedHook() {
if (requesting) {
return
}
requesting = true
requestAnimationFrame(() => {
jsHookAfterNativeCall()
requesting = false
})
}
2019-12-19 11:52:15 +08:00
initDoric()