diff --git a/src/ainize.ts b/src/ainize.ts index c31b709..c66ab5f 100644 --- a/src/ainize.ts +++ b/src/ainize.ts @@ -1,10 +1,12 @@ import Ain from "@ainblockchain/ain-js"; import * as NodeCache from "node-cache"; import Middleware from "./middlewares/middleware"; -import { getBlockChainEndpoint } from "./constants"; +import { DEFAULT_BILLING_CONFIG, getBlockChainEndpoint } from "./constants"; import Handler from "./handlers/handler"; -import AppController from "./controller/appController"; +import AppController from "./controllers/appController"; import Model from "./model"; +import { deployConfig } from "./types/type"; +import AinModule from "./ain"; export default class Ainize { private cache: NodeCache; ain: Ain; @@ -12,7 +14,7 @@ export default class Ainize { handler: Handler; appController: AppController = AppController.getInstance(); - constructor(chainId: 1|0) { + constructor(chainId: 1 | 0) { const blockChainEndpoint = getBlockChainEndpoint(chainId); this.ain = new Ain(blockChainEndpoint, chainId); this.cache = new NodeCache(); @@ -21,10 +23,21 @@ export default class Ainize { } // FIXME(yoojin): add config type and change param type. - deploy(modelName: string, config: any) { + deploy({modelName, billingConfig, serviceUrl}: deployConfig) { // TODO(yoojin, woojae): Deploy container, advanced. - // TODO(yoojin): add createApp - // this.appController.createApp(modelName, ) + const deployer = AinModule.getInstance().getAddress(); + if (!billingConfig) { + billingConfig = { + ...DEFAULT_BILLING_CONFIG, + depositAddress: deployer, + } + } + // NOTE(yoojin): For test. We make fixed url on service. + if (!serviceUrl) { + serviceUrl = `https://${modelName}.ainetwork.xyz`; + } + + this.appController.createApp({ appName: modelName, serviceUrl, billingConfig }) } model(modelName: string) { diff --git a/src/constants.ts b/src/constants.ts index e9b9c8b..3c75390 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,4 +1,6 @@ -export const getBlockChainEndpoint = (chainId:number) =>{ +import { appBillingConfig } from "./types/type" + +export const getBlockChainEndpoint = (chainId: number) =>{ return chainId === 1 ? "https://mainnet-event.ainetwork.ai" : "https://testnet-event.ainetwork.ai" } @@ -33,32 +35,32 @@ export const defaultAppRules = (appName: string): { [type: string]: { ref: strin value: { ".rule": { write: "util.isAppAdmin(`" + `${appName}` + "`, auth.addr, getValue) === true" - } - } + }, + }, }, deposit: { ref: `${Path.app(appName).depositOfUser("$userAddress")}/$transferKey`, value: { ".rule": { write: "data === null && util.isNumber(newData) && getValue(`/transfer/` + $userAddress + `/` + getValue(`/apps/" + `${appName}` + "/billingConfig/depositAddress`) + `/` + $transferKey + `/value`) === newData" - } - } + }, + }, }, balance: { ref: Path.app(appName).balanceOfUser("$userAddress"), value: { ".rule": { write: "(util.isAppAdmin(`" + `${appName}` + "`, auth.addr, getValue) === true) && util.isNumber(newData) && newData > 0", - } - } + }, + }, }, balanceHistory: { ref: `${rootRef}/balance/$userAddress/history/$timestamp_and_type`, value: { ".rule": { write: "util.isAppAdmin(`" + `${appName}` + "`, auth.addr, getValue) === true && util.isDict(newData) && util.isNumber(newData.amount) && (newData.type === 'DEPOSIT' || newData.type === 'USAGE')" - } - } + }, + }, }, request: { ref: Path.app(appName).request("$userAddress", "$requestKey"), @@ -67,15 +69,15 @@ export const defaultAppRules = (appName: string): { [type: string]: { ref: strin write: "auth.addr === $userAddress && getValue(`/apps/" + `${appName}` + "/balance/` + $userAddress + `/balance`) !== null && " + "(!util.isEmpty(getValue(`/apps/" + `${appName}` + "/billingConfig/minCost`))) && (getValue(`/apps/" + `${appName}` + "/balance/` + $userAddress + `/balance`) >= getValue(`/apps/" + `${appName}` + "/billingConfig/minCost`))" - } - } + }, + }, }, response: { ref: Path.app(appName).response("userAddress", "$requestKey"), value: { ".rule": { write: "util.isAppAdmin(`" + `${appName}` + "`, auth.addr, getValue) === true && util.isDict(newData) && util.isString(newData.status)" - } + }, }, }, billingConfig: { @@ -85,11 +87,16 @@ export const defaultAppRules = (appName: string): { [type: string]: { ref: strin write: "util.isAppAdmin(`" + `${appName}` + "`, auth.addr, getValue) === true && util.isDict(newData) && util.isString(newData.depositAddress) && " + "util.isDict(newData.service) && util.isDict(newData.service.default) && util.isNumber(newData.service.default.costPerToken) && util.isNumber(newData.service.default.minCost) && " + "util.isEmpty(newData.service.default.maxCost) || (util.isNumber(newData.service.default.maxCost) && newData.service.default.maxCost >= newData.service.default.minCost)", - } - } + }, + }, }, - } + }; } +export const DEFAULT_BILLING_CONFIG: Omit = { + costPerToken: 0, + minCost: 0, +}; + export const SECOND = 1000; export const HANDLER_HEARBEAT_INTERVAL = 15 * SECOND; diff --git a/src/controllers/appController.ts b/src/controllers/appController.ts index 1172836..8a65579 100644 --- a/src/controllers/appController.ts +++ b/src/controllers/appController.ts @@ -1,6 +1,6 @@ import { SetOperation } from "@ainblockchain/ain-js/lib/types"; import { Path, defaultAppRules } from "../constants"; -import { appBillingConfig, setRuleParam, setTriggerFunctionParm, triggerFunctionConfig } from "../types/type"; +import { ContainerStatus, appBillingConfig, createAppConfig, setRuleParam, setTriggerFunctionParm, triggerFunctionConfig } from "../types/type"; import { buildSetOperation, buildTxBody } from "../utils/builder"; import AinModule from '../ain'; @@ -22,7 +22,7 @@ export default class AppController { * @param {setDefaultFlag} setDefaultFlag - Set true which you wan to set config as default. * @returns Result of transaction. */ - async createApp(appName: string, serviceUrl: string) { + async createApp({ appName, serviceUrl, billingConfig }: createAppConfig) { const setRuleOps: SetOperation[] = []; const setFunctionOps: SetOperation[] = []; const setBillingConfigOps: SetOperation[] = [] ; @@ -39,20 +39,17 @@ export default class AppController { const value = this.buildSetFunctionValue(depositParam); const funcOp = buildSetOperation("SET_FUNCTION", depositParam.ref, value); setFunctionOps.push(funcOp); - const depositAddress = this.ain.getDefaultAccount()!.address; - const defaultConfig: appBillingConfig = { - depositAddress, - costPerToken: 0, - minCost: 0, - } - const configOp = this.buildSetAppBillingConfigOp(appName, defaultConfig); + const configOp = this.buildSetAppBillingConfigOp(appName, billingConfig); setBillingConfigOps.push(configOp); + const statusOp = this.buildSetContainerStatusOp(appName, ContainerStatus.RUNNING); + const txBody = buildTxBody([ createAppOp, ...setRuleOps, ...setFunctionOps, ...setBillingConfigOps, + statusOp, ]); return await this.ain.sendTransaction(txBody); } @@ -118,6 +115,12 @@ export default class AppController { return await this.ain.sendTransaction(txBody); } + async setContainerStatus(appName: string, status: ContainerStatus) { + const op = this.buildSetContainerStatusOp(appName, status); + const txBody = buildTxBody(op); + return await this.ain.sendTransaction(txBody); + } + /** * Add admin on app. * @param {string} appName @@ -142,7 +145,7 @@ export default class AppController { return await this.ain.sendTransaction(txBody); } - /** + /** * Check cost of request and check if account can pay. You should use this function before send or handle request. * If you don't set address, it will use default account's address. * @param {string} appName - App name you want to request service to. @@ -172,6 +175,11 @@ export default class AppController { return await this.ain.getValue(balancePath); } + private buildSetContainerStatusOp(appName: string, status: ContainerStatus) { + const path = Path.app(appName).status(); + return buildSetOperation("SET_VALUE", path, status); + } + private buildSetAppBillingConfigOp(appName: string, config: appBillingConfig) { const path = Path.app(appName).billingConfig(); return buildSetOperation("SET_VALUE", path, config); diff --git a/src/types/type.ts b/src/types/type.ts index 2511425..c797106 100644 --- a/src/types/type.ts +++ b/src/types/type.ts @@ -68,4 +68,21 @@ export type deposit = { transferValue: number, appName: string, requesterAddress: string, -} \ No newline at end of file +} + +export type deployConfig = { + modelName: string, + billingConfig?: appBillingConfig, + serviceUrl?: string, // NOTE(yoojin): for test. +} + +export type createAppConfig = { + appName: string, + billingConfig: appBillingConfig, + serviceUrl: string, +} + +export enum ContainerStatus { + RUNNING = "RUNNING", + STOP = "STOP", +}