-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
experimental mode moving along, ensuring stable is only stable
- Loading branch information
Showing
20 changed files
with
570 additions
and
75 deletions.
There are no files selected for viewing
73 changes: 73 additions & 0 deletions
73
src/build/experimental/commands/compile/candid_and_method_meta.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { IOType } from 'child_process'; | ||
import { readFile } from 'fs/promises'; | ||
import { join } from 'path'; | ||
|
||
import { handleAutomaticAndCustom } from '../../../stable/commands/compile/candid_and_method_meta'; | ||
import { AZLE_PACKAGE_PATH } from '../../../stable/utils/global_paths'; | ||
import { | ||
CandidAndMethodMeta, | ||
CandidGen, | ||
EnvVars, | ||
MethodMeta | ||
} from '../../../stable/utils/types'; | ||
|
||
export async function getCandidAndMethodMeta( | ||
canisterName: string, | ||
candidGen: CandidGen | undefined, | ||
canisterPath: string, | ||
candidPath: string, | ||
js: string, | ||
ioType: IOType, | ||
envVars: EnvVars | ||
): Promise<CandidAndMethodMeta> { | ||
if ( | ||
candidGen === undefined || | ||
candidGen === 'automatic' || | ||
candidGen === 'custom' | ||
) { | ||
return await handleAutomaticAndCustom( | ||
candidGen, | ||
candidPath, | ||
canisterName, | ||
ioType, | ||
js, | ||
envVars, | ||
canisterPath | ||
); | ||
} | ||
|
||
if (candidGen === 'http') { | ||
return await handleHttp(); | ||
} | ||
|
||
throw new Error(`dfx.json: "candid_gen": "${candidGen}" is not supported`); | ||
} | ||
|
||
async function handleHttp(): Promise<CandidAndMethodMeta> { | ||
const candid = ( | ||
await readFile(join(AZLE_PACKAGE_PATH, 'server.did')) | ||
).toString(); | ||
|
||
const methodMeta: MethodMeta = { | ||
queries: [ | ||
{ | ||
name: 'http_request', | ||
index: 0, | ||
composite: true | ||
} | ||
], | ||
updates: [ | ||
{ | ||
name: 'http_request_update', | ||
index: 1 | ||
} | ||
], | ||
init: { name: 'init', index: 2 }, | ||
post_upgrade: { name: 'postUpgrade', index: 3 } | ||
}; | ||
|
||
return { | ||
candid, | ||
methodMeta | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { join } from 'path'; | ||
|
||
import { version } from '../../../../../package.json'; | ||
import { getContext as getStableContext } from '../../../stable/commands/compile/get_context'; | ||
import { GLOBAL_AZLE_CONFIG_DIR } from '../../../stable/utils/global_paths'; | ||
import { CanisterConfig } from '../../../stable/utils/types'; | ||
import { Context } from '../../utils/types'; | ||
|
||
export function getContext( | ||
canisterName: string, | ||
canisterConfig: CanisterConfig | ||
): Context { | ||
const stableContext = getStableContext(canisterName, canisterConfig); | ||
|
||
const esmAliases = canisterConfig.custom?.esm_aliases ?? {}; | ||
const esmExternals = canisterConfig.custom?.esm_externals ?? []; | ||
|
||
const wasmedgeQuickJsName = `wasmedge-quickjs_${version}`; | ||
|
||
const wasmedgeQuickJsPath = join( | ||
GLOBAL_AZLE_CONFIG_DIR, | ||
wasmedgeQuickJsName | ||
); | ||
|
||
return { | ||
...stableContext, | ||
esmAliases, | ||
esmExternals, | ||
wasmedgeQuickJsPath | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,65 @@ | ||
import { IOType } from 'child_process'; | ||
|
||
import { | ||
createHiddenAzleDirectories, | ||
writeGeneratedFiles | ||
} from '../../../stable/commands/compile'; | ||
import { getWasmBinary } from '../../../stable/commands/compile/wasm_binary'; | ||
import { CanisterConfig } from '../../../stable/utils/types'; | ||
import { getCandidAndMethodMeta } from './candid_and_method_meta'; | ||
import { getContext } from './get_context'; | ||
import { compile as compileJavaScript } from './javascript'; | ||
|
||
export async function runCommand( | ||
_canisterName: string, | ||
_canisterConfig: CanisterConfig | ||
canisterName: string, | ||
canisterConfig: CanisterConfig, | ||
ioType: IOType | ||
): Promise<void> { | ||
throw new Error('Azle: experimental build process not yet implemented'); | ||
const { | ||
canisterPath, | ||
candidPath, | ||
envVars, | ||
esmAliases, | ||
esmExternals, | ||
main, | ||
wasmBinaryPath, | ||
wasmedgeQuickJsPath | ||
} = getContext(canisterName, canisterConfig); | ||
|
||
await createHiddenAzleDirectories(canisterPath); | ||
|
||
const javaScript = await compileJavaScript( | ||
main, | ||
wasmedgeQuickJsPath, | ||
esmAliases, | ||
esmExternals | ||
); | ||
|
||
const { candid, methodMeta } = await getCandidAndMethodMeta( | ||
canisterName, | ||
canisterConfig.custom?.candid_gen, | ||
canisterPath, | ||
candidPath, | ||
javaScript, | ||
ioType, | ||
envVars | ||
); | ||
|
||
const wasmBinary = await getWasmBinary( | ||
canisterName, | ||
ioType, | ||
javaScript, | ||
envVars, | ||
canisterPath, | ||
methodMeta | ||
); | ||
|
||
await writeGeneratedFiles( | ||
canisterPath, | ||
candidPath, | ||
wasmBinaryPath, | ||
candid, | ||
javaScript, | ||
wasmBinary | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
import { BuildOptions } from 'esbuild'; | ||
import { join } from 'path'; | ||
|
||
import { | ||
bundle, | ||
getBuildOptions as getStableBuildOptions | ||
} from '../../../stable/commands/compile/javascript'; | ||
import { AZLE_PACKAGE_PATH } from '../../../stable/utils/global_paths'; | ||
|
||
export async function compile( | ||
main: string, | ||
wasmedgeQuickJsPath: string, | ||
esmAliases: Record<string, string>, | ||
esmExternals: string[] | ||
): Promise<string> { | ||
const prelude = getPrelude(main); | ||
const buildOptions = getBuildOptions( | ||
prelude, | ||
wasmedgeQuickJsPath, | ||
esmAliases, | ||
esmExternals | ||
); | ||
const bundled = await bundle(buildOptions); | ||
|
||
return bundled; | ||
} | ||
|
||
export function getPrelude(main: string): string { | ||
return /*TS*/ ` | ||
import 'azle/src/lib/stable/globals'; | ||
import 'azle/src/lib/experimental/globals'; | ||
import 'reflect-metadata'; | ||
// TODO remove the ethersGetUrl registration once we implement lower-level http for ethers | ||
import { ethersGetUrl, Server } from 'azle/src/lib/experimental'; | ||
import { ethers } from 'ethers'; | ||
ethers.FetchRequest.registerGetUrl(ethersGetUrl); | ||
import { DidVisitor, getDefaultVisitorData, IDL, toDidString } from 'azle'; | ||
export { Principal } from '@dfinity/principal'; | ||
export * from './${main}'; | ||
import * as CanisterMethods from './${main}'; | ||
if (isClassSyntaxExport(CanisterMethods)) { | ||
if (globalThis._azleWasmtimeCandidEnvironment === false) { | ||
const canister = new CanisterMethods.default(); | ||
globalThis._azleCanisterClassInstance = canister; | ||
} | ||
const canisterIdlType = IDL.Service(globalThis._azleCanisterMethodIdlTypes); | ||
const candid = canisterIdlType.accept(new DidVisitor(), { | ||
...getDefaultVisitorData(), | ||
isFirstService: true, | ||
systemFuncs: globalThis._azleInitAndPostUpgradeIdlTypes | ||
}); | ||
globalThis.candidInfoFunction = () => { | ||
return JSON.stringify({ | ||
candid: toDidString(candid), | ||
canisterMethods: globalThis._azleCanisterMethods | ||
}); | ||
}; | ||
globalThis.exports.canisterMethods = globalThis._azleCanisterMethods; | ||
} | ||
else { | ||
// TODO This setTimeout is here to allow asynchronous operations during canister initialization | ||
// for Server canisters that have chosen not to use export default Server | ||
// This seems to work no matter how many async tasks are awaited, but I am still unsure about how it will | ||
// behave in all async situations | ||
setTimeout(() => { | ||
const canisterMethods = CanisterMethods.default !== undefined ? CanisterMethods.default() : Server(() => globalThis._azleNodeServer)(); | ||
globalThis.candidInfoFunction = () => { | ||
const candidInfo = canisterMethods.getIdlType([]).accept(new DidVisitor(), { | ||
...getDefaultVisitorData(), | ||
isFirstService: true, | ||
systemFuncs: canisterMethods.getSystemFunctionIdlTypes() | ||
}); | ||
return JSON.stringify({ | ||
candid: toDidString(candidInfo), | ||
canisterMethods: { | ||
// TODO The spread is because canisterMethods is a function with properties | ||
// TODO we should probably just grab the props out that we need | ||
...canisterMethods | ||
} | ||
}); | ||
}; | ||
// TODO I do not know how to get the module exports yet with wasmedge_quickjs | ||
globalThis.exports.canisterMethods = canisterMethods; | ||
}); | ||
} | ||
function isClassSyntaxExport(module) { | ||
const isNothing = module === undefined || module.default === undefined; | ||
const isFunctionalSyntaxExport = | ||
module?.default?.isCanister === true || | ||
module?.default?.isRecursive === true; | ||
return !isNothing && !isFunctionalSyntaxExport; | ||
} | ||
`; | ||
} | ||
|
||
export function getBuildOptions( | ||
ts: string, | ||
wasmedgeQuickJsPath: string, | ||
esmAliases: Record<string, string>, | ||
esmExternals: string[] | ||
): BuildOptions { | ||
const finalWasmedgeQuickJsPath = | ||
process.env.AZLE_WASMEDGE_QUICKJS_DIR ?? wasmedgeQuickJsPath; | ||
|
||
const externalImplemented = [ | ||
'_node:fs', | ||
'_node:os', | ||
'_node:crypto', | ||
'qjs:os', | ||
'_encoding', | ||
'wasi_net', | ||
'wasi_http' | ||
]; | ||
|
||
// These are modules that should not be included in the build from the Azle side (our side) | ||
const externalNotImplementedAzle: string[] = []; | ||
|
||
// These are modules that should not be included in the build from the developer side | ||
// These are specified in the dfx.json canister object esm_externals property | ||
const externalNotImplementedDev = esmExternals; | ||
|
||
// These will cause runtime errors if their functionality is dependend upon | ||
const externalNotImplemented = [ | ||
...externalNotImplementedAzle, | ||
...externalNotImplementedDev | ||
]; | ||
|
||
const customJsModulesPath = join( | ||
AZLE_PACKAGE_PATH, | ||
'src', | ||
'compiler', | ||
'custom_js_modules' | ||
); | ||
|
||
const stableBuildOptions = getStableBuildOptions(ts); | ||
|
||
return { | ||
...stableBuildOptions, | ||
alias: { | ||
internal: `${finalWasmedgeQuickJsPath}/modules/internal`, | ||
util: `${finalWasmedgeQuickJsPath}/modules/util`, | ||
fs: `${finalWasmedgeQuickJsPath}/modules/fs`, | ||
fmt: `${finalWasmedgeQuickJsPath}/modules/fmt`, | ||
assert: `${finalWasmedgeQuickJsPath}/modules/assert.js`, | ||
buffer: `${finalWasmedgeQuickJsPath}/modules/buffer.js`, | ||
path: `${finalWasmedgeQuickJsPath}/modules/path.js`, | ||
stream: `${finalWasmedgeQuickJsPath}/modules/stream.js`, | ||
process: `${finalWasmedgeQuickJsPath}/modules/process.js`, | ||
url: `${finalWasmedgeQuickJsPath}/modules/url.js`, | ||
events: `${finalWasmedgeQuickJsPath}/modules/events.js`, | ||
string_decoder: `${finalWasmedgeQuickJsPath}/modules/string_decoder.js`, | ||
punycode: `${finalWasmedgeQuickJsPath}/modules/punycode.js`, | ||
querystring: `${finalWasmedgeQuickJsPath}/modules/querystring.js`, | ||
whatwg_url: `${finalWasmedgeQuickJsPath}/modules/whatwg_url.js`, | ||
encoding: `${finalWasmedgeQuickJsPath}/modules/encoding.js`, | ||
http: `${finalWasmedgeQuickJsPath}/modules/http.js`, | ||
os: `${finalWasmedgeQuickJsPath}/modules/os.js`, | ||
// crypto: `${finalWasmedgeQuickJsPath}/modules/crypto.js`, // TODO waiting on wasi-crypto | ||
crypto: 'crypto-browserify', // TODO we really want the wasmedge-quickjs version once wasi-crypto is working | ||
zlib: 'pako', | ||
'internal/deps/acorn/acorn/dist/acorn': join( | ||
customJsModulesPath, | ||
'acorn', | ||
'acorn.ts' | ||
), // TODO acorn stuff is a bug, wasmedge-quickjs should probably add these files | ||
'internal/deps/acorn/acorn-walk/dist/walk': join( | ||
customJsModulesPath, | ||
'acorn', | ||
'walk.ts' | ||
), // TODO acorn stuff is a bug, wasmedge-quickjs should probably add these files | ||
perf_hooks: join(customJsModulesPath, 'perf_hooks.ts'), | ||
async_hooks: join(customJsModulesPath, 'async_hooks.ts'), | ||
https: join(customJsModulesPath, 'https.ts'), | ||
...esmAliases | ||
}, | ||
external: [...externalImplemented, ...externalNotImplemented] | ||
}; | ||
} |
19 changes: 19 additions & 0 deletions
19
src/build/experimental/commands/compile/wasm_binary/compile.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { IOType } from 'child_process'; | ||
|
||
import { execSyncPretty } from '../../../../stable/utils/exec_sync_pretty'; | ||
|
||
export function compile( | ||
wasmDest: string, | ||
canisterName: string, | ||
stdio: IOType | ||
): void { | ||
execSyncPretty( | ||
`CARGO_TARGET_DIR=target cargo build --target wasm32-wasi --manifest-path .azle/${canisterName}/canister/Cargo.toml --release --features "experimental"`, | ||
stdio | ||
); | ||
|
||
execSyncPretty( | ||
`wasi2ic target/wasm32-wasi/release/canister.wasm ${wasmDest}`, | ||
stdio | ||
); | ||
} |
Oops, something went wrong.