Skip to content

Commit

Permalink
Merge pull request #11 from pawanpaudel93/feat/on-boot
Browse files Browse the repository at this point in the history
feat: add on boot process initialization config during deployment
  • Loading branch information
pawanpaudel93 authored Jan 12, 2025
2 parents 6b4a619 + 604dd6e commit aacf5be
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 111 deletions.
29 changes: 20 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Arguments:
Options:
-V, --version output the version number
-n, --name [name] Specify the process name. (default: "default")
-w, --wallet [wallet] Path to the wallet JWK file.
-w, --wallet [wallet] Path to the wallet JWK file. (Autogenerated if not passed)
-l, --lua-path [luaPath] Specify the Lua modules path seperated by semicolon.
-d, --deploy [deploy] List of deployment configuration names, separated by commas.
-b, --build [build] List of deployment configuration names, separated by commas.
Expand All @@ -90,6 +90,7 @@ Options:
--retry-count [count] Number of retries for deploying contract. (default: 10)
--retry-delay [delay] Delay between retries in milliseconds. (default: 3000)
--minify Reduce the size of the contract before deployment. (default: false)
--on-boot Load contract when process is spawned. (default: false)
-h, --help display help for command
```
Expand All @@ -108,6 +109,12 @@ ao-deploy process.lua -n tictactoe -w wallet.json --tags name1:value1 name2:valu
ao-deploy process.lua -n tictactoe -w wallet.json --tags name1:value1 name2:value2 --minify
```
#### Example: Deploy contract with on-boot
```sh
ao-deploy process.lua -n tictactoe -w wallet.json --tags name1:value1 name2:value2 --on-boot
```
#### Example: Deploy contracts with configuration
Here is an example using a deployment configuration:
Expand Down Expand Up @@ -257,10 +264,11 @@ async function main() {
}
});
const processUrl = `https://www.ao.link/#/entity/${processId}`;
const messageUrl = `https://www.ao.link/#/message/${messageId}`;
console.log(
`\nDeployed Process: ${processUrl} \nDeployment Message: ${messageUrl}`
);
console.log(`Deployed Process: ${processUrl}`);
if (messageId) {
const messageUrl = `https://www.ao.link/#/message/${messageId}`;
console.log(`Deployment Message: ${messageUrl}`);
}
} catch (error: any) {
console.log(
`Deployment failed!: ${error?.message ?? "Failed to deploy contract!"}\n`
Expand All @@ -287,6 +295,8 @@ The `deployContract` function accepts the following parameters within the Deploy
- `processId` (optional): The process id of existing process.
- `minify` (optional): Reduce the size of the contract before deployment.
- `contractTransformer` (optional): Custom function to transform source code before deployment.
- `onBoot` (optional): Load contract when process is spawned. (default: false)
- `silent` (optional): Disable logging to console. (default: false)
#### Example: deployContracts
Expand Down Expand Up @@ -326,10 +336,11 @@ async function main() {
if (result.status === "fulfilled") {
const { processId, messageId } = result.value;
const processUrl = `https://www.ao.link/#/entity/${processId}`;
const messageUrl = `https://www.ao.link/#/message/${messageId}`;
console.log(
`\nDeployed Process: ${processUrl} \nDeployment Message: ${messageUrl}`
);
console.log(`Deployed Process: ${processUrl}`);
if (messageId) {
const messageUrl = `https://www.ao.link/#/message/${messageId}`;
console.log(`Deployment Message: ${messageUrl}`);
}
} else {
console.log(`Failed to deploy contract!: ${result.reason}\n`);
}
Expand Down
Empty file added hello.lua
Empty file.
13 changes: 8 additions & 5 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,15 @@ function getPackageJson() {
function logDeploymentDetails(result: DeployResult) {
const { messageId, processId, isNewProcess, configName } = result;
const processUrl = chalk.green(`${aoExplorerUrl}/#/entity/${processId}`);
const messageUrl = chalk.green(`${aoExplorerUrl}/#/message/${messageId}`);
const logger = Logger.init(configName);

console.log("");
if (isNewProcess) {
logger.log(`Deployed Process: ${processUrl}`);
}
logger.log(`Deployment Message: ${messageUrl}`);
if (messageId) {
const messageUrl = chalk.green(`${aoExplorerUrl}/#/message/${messageId}`);
logger.log(`Deployment Message: ${messageUrl}`);
}
}

function logBundleDetails(result: BundleResult) {
Expand Down Expand Up @@ -151,7 +152,8 @@ program
parseToInt,
3000
)
.option("--minify", "Reduce the size of the contract before deployment.");
.option("--minify", "Reduce the size of the contract before deployment.")
.option("--on-boot", "Load contract when process is spawned.");

program.parse(process.argv);

Expand Down Expand Up @@ -196,7 +198,8 @@ async function deploymentHandler() {
cuUrl: options.cuUrl,
muUrl: options.muUrl
},
minify: options.minify
minify: options.minify,
onBoot: options.onBoot
});
logDeploymentDetails(result);
} else {
Expand Down
39 changes: 19 additions & 20 deletions src/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,19 +128,36 @@ export class ConfigManager {
"wallet",
"outDir"
];
const optionalBooleanProps: (keyof DeployConfig)[] = [
"sqlite",
"silent",
"minify",
"onBoot"
];

optionalAddressProps.forEach((prop) => {
if (deployConfig[prop] && !isArweaveAddress(deployConfig[prop])) {
throw new Error(
`Invalid optional property "${prop}" in configuration for "${keyName}": ${jsonStringify(deployConfig[prop])}`
`Invalid "${prop}" value in configuration for "${keyName}": ${jsonStringify(deployConfig[prop])}`
);
}
});

optionalStringProps.forEach((prop) => {
if (deployConfig[prop] && !this.#isString(deployConfig[prop])) {
throw new Error(
`Invalid optional property "${prop}" in configuration for "${keyName}": ${jsonStringify(deployConfig[prop])}`
`Invalid "${prop}" value in configuration for "${keyName}": ${jsonStringify(deployConfig[prop])}`
);
}
});

optionalBooleanProps.forEach((prop) => {
if (
deployConfig[prop] !== undefined &&
typeof deployConfig[prop] !== "boolean"
) {
throw new Error(
`Invalid "${prop}" value in configuration for "${keyName}": ${jsonStringify(deployConfig[prop])}`
);
}
});
Expand Down Expand Up @@ -185,24 +202,6 @@ export class ConfigManager {
);
}

if (
deployConfig.sqlite !== undefined &&
typeof deployConfig.sqlite !== "boolean"
) {
throw new Error(
`Invalid sqlite value in configuration for "${name}": ${jsonStringify(deployConfig.sqlite)}`
);
}

if (
deployConfig.minify !== undefined &&
typeof deployConfig.minify !== "boolean"
) {
throw new Error(
`Invalid minify value in configuration for "${name}": ${jsonStringify(deployConfig.minify)}`
);
}

if (
deployConfig.contractTransformer !== undefined &&
typeof deployConfig.contractTransformer !== "function"
Expand Down
125 changes: 73 additions & 52 deletions src/lib/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,9 @@ export class DeploymentsManager {
sqlite,
services,
minify,
contractTransformer
contractTransformer,
onBoot,
silent = false
}: DeployConfig): Promise<DeployResult> {
name = name || "default";
configName = configName || name;
Expand All @@ -140,7 +142,7 @@ export class DeploymentsManager {
delay: parseToInt(retry?.delay, 3000)
};

const logger = new Logger(configName);
const logger = new Logger(configName, silent);
const aosConfig = await this.#getAosConfig();
module = isArweaveAddress(module)
? module!
Expand Down Expand Up @@ -168,7 +170,20 @@ export class DeploymentsManager {

const isNewProcess = !processId;

if (!processId) {
const loader = new LuaProjectLoader(configName, luaPath, silent);
let contractSrc = await loader.loadContract(contractPath);

if (contractTransformer && typeof contractTransformer === "function") {
logger.log("Transforming contract...", false, false);
contractSrc = await contractTransformer(contractSrc);
}

if (minify) {
logger.log("Minifying contract...", false, false);
contractSrc = await loader.minifyContract(contractSrc);
}

if (isNewProcess) {
logger.log("Spawning new process...", false, true);
tags = Array.isArray(tags) ? tags : [];
tags = [
Expand All @@ -179,6 +194,11 @@ export class DeploymentsManager {
...tags
];

if (onBoot) {
logger.log(`Deploying: ${contractPath}`, false, true);
tags = [...tags, { name: "On-Boot", value: "Data" }];
}

if (cron) {
this.#validateCron(cron);
tags = [
Expand All @@ -188,72 +208,73 @@ export class DeploymentsManager {
];
}

const data = "1984";
const data = onBoot ? contractSrc : "1984";
processId = await retryWithDelay(
() => aoInstance.spawn({ module, signer, tags, data, scheduler }),
retry.count,
retry.delay
);

await pollForProcessSpawn({ processId });
} else {
logger.log("Updating existing process...", false, true);
}

const loader = new LuaProjectLoader(configName, luaPath);
let contractSrc = await loader.loadContract(contractPath);

if (contractTransformer && typeof contractTransformer === "function") {
logger.log("Transforming contract...", false, false);
contractSrc = await contractTransformer(contractSrc);
}

if (minify) {
logger.log("Minifying contract...", false, false);
contractSrc = await loader.minifyContract(contractSrc);
if (onBoot) {
return { name, processId, isNewProcess, configName };
}
}

logger.log(`Deploying: ${contractPath}`, false, true);
// Load contract to process
const messageId = await retryWithDelay(
async () =>
aoInstance.message({
process: processId,
tags: [{ name: "Action", value: "Eval" }],
data: contractSrc,
signer
}),
retry.count,
retry.delay
);
let messageId: string;
if (!onBoot || !isNewProcess) {
if (!isNewProcess) {
logger.log("Updating existing process...", false, true);
}
logger.log(`Deploying: ${contractPath}`, false, true);
// Load contract to process
messageId = await retryWithDelay(
async () =>
aoInstance.message({
process: processId!,
tags: [{ name: "Action", value: "Eval" }],
data: contractSrc,
signer
}),
retry.count,
retry.delay
);

const { Output, Error: error } = await retryWithDelay(
async () =>
aoInstance.result({
process: processId,
message: messageId
}),
retry.count,
retry.delay
);
const { Output, Error: error } = await retryWithDelay(
async () =>
aoInstance.result({
process: processId!,
message: messageId
}),
retry.count,
retry.delay
);

let errorMessage = null;
let errorMessage = null;

if (Output?.data?.output) {
errorMessage = Output.data.output;
} else if (error) {
if (typeof error === "object" && Object.keys(error).length > 0) {
errorMessage = JSON.stringify(error);
} else {
errorMessage = String(error);
if (Output?.data?.output) {
errorMessage = Output.data.output;
} else if (error) {
if (typeof error === "object" && Object.keys(error).length > 0) {
errorMessage = JSON.stringify(error);
} else {
errorMessage = String(error);
}
}
}

if (errorMessage) {
throw new Error(errorMessage);
if (errorMessage) {
throw new Error(errorMessage);
}
}

return { name, processId, messageId, isNewProcess, configName };
return {
name,
processId: processId!,
messageId: messageId!,
isNewProcess,
configName
};
}

/**
Expand Down
24 changes: 13 additions & 11 deletions src/lib/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ export class LuaProjectLoader {
#luaPath: string;
#logger: Logger;

constructor(name: string, luaPath?: string) {
constructor(name: string, luaPath?: string, silent: boolean = false) {
this.#luaPath = luaPath || "";
this.#logger = Logger.init(name);
this.#logger = Logger.init(name, silent);
}

async #fileExists(path: string): Promise<boolean> {
Expand Down Expand Up @@ -193,15 +193,17 @@ export class LuaProjectLoader {
false,
true
);
console.log(
chalk.dim(
createFileTree([
...projectStructure.map((m) => m.path),
`${filePath} ${chalk.reset(chalk.bgGreen(" MAIN "))}`
])
)
);
console.log("");
if (!this.#logger.silent) {
console.log(
chalk.dim(
createFileTree([
...projectStructure.map((m) => m.path),
`${filePath} ${chalk.reset(chalk.bgGreen(" MAIN "))}`
])
)
);
console.log("");
}
}

return line.trim();
Expand Down
Loading

0 comments on commit aacf5be

Please sign in to comment.