Skip to content

Commit

Permalink
Solve issues
Browse files Browse the repository at this point in the history
  • Loading branch information
viferga committed Apr 9, 2024
1 parent 1b8b77c commit a9b1dea
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 118 deletions.
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,45 @@

Reimplementation of MetaCall FaaS platform written in TypeScript. This project requires MetaCall installed in order to run it. For more information about installation: https://github.com/metacall/install

### Development:
### Development

```sh
npm install
npm start
```

### About Project :
### About Project

MetaCall organization has its own cloud platform known as [MetaCall Hub](https://metacall.io/), a production-ready and high-performance FaaS/Cloud platform where you can deploy services, web apps, and lambdas in seconds. However, the ```Real``` version of MetaCall FaaS is commercialized and requires a plan to deploy your polyglot applications, which can be found [Here](https://metacall.io/pricing/).
MetaCall organization has its own cloud platform known as [MetaCall Hub](https://metacall.io/), a production-ready and high-performance FaaS/Cloud platform where you can deploy services, web apps, and lambdas in seconds. However, the `Real` version of MetaCall FaaS is commercialized and requires a plan to deploy your polyglot applications, which can be found [Here](https://metacall.io/pricing/).

When referring to the ```Real``` version of MetaCall FaaS, it should be noted that this refers to the commercialized FaaS cloud service, whereas ```Local``` refers to the mimic version.
When referring to the `Real` version of MetaCall FaaS, it should be noted that this refers to the commercialized FaaS cloud service, whereas `Local` refers to the mimic version.

Soon, we realized that many contributors joining the community needed an paid account on the ```Real FaaS``` for testing their polyglot applications. To remove this barrier, we proposed a project that would mimic the ```Real FaaS```.
Soon, we realized that many contributors joining the community needed an paid account on the `Real FaaS` for testing their polyglot applications. To remove this barrier, we proposed a project that would mimic the `Real FaaS`.

With this project, developers can now use it to deploy and test their polyglot applications (built using [MetaCall Core](https://github.com/metacall/core)), web apps, and lambdas. The process is simple:

- Step 1 : Spin up the "Local FaaS" by running the following command:
- Step 1 : Spin up the "Local FaaS" by running the following command:

```sh
cd faas
npm start
```

- Step 2 : Install the [metacall-deploy](https://www.npmjs.com/package/@metacall/deploy) NPM package, and wire the ```--dev``` flag with the ```metacall-deploy``` command in your application directory using the following command:
- Step 2 : Install the [metacall-deploy](https://www.npmjs.com/package/@metacall/deploy) NPM package, and wire the `--dev` flag with the `metacall-deploy` command in your application directory using the following command:

```sh
cd move-to-application-directory
metacall-deploy --dev
```

### Things that need to be implemented:
### Things that need to be implemented

- In order to mimic the "Real FaaS", we need to create all the API endpoints that the "Real FaaS" supports, which can be found listed [Here](https://github.com/metacall/protocol/blob/master/src/protocol.ts).
- In order to mimic the "Real FaaS", we need to create all the API endpoints that the "Real FaaS" supports, which can be found listed [Here](https://github.com/metacall/protocol/blob/master/src/protocol.ts).

### Important Note

- This project is still under development and there is one extra thing you need to install before running this project and its [MetaCall Core](https://github.com/metacall/core/blob/develop/docs/README.md#41-installation).

- This project is developed using [MetaCall Core] itself in order to provide polyglot support, we are using its [Node Port](https://github.com/metacall/core/tree/develop/source/ports/node_port) of this library to use all the functions and methods ```MetaCall Core C API``` provides.
- This project is still under development and there is one extra thing you need to install before running this project and its [MetaCall Core](https://github.com/metacall/core/blob/develop/docs/README.md#41-installation).

- Also, [Here](https://github.com/metacall/faas/blob/master/types/metacall.d.ts) are all the functions of ```MetaCall Core``` we are using.
- This project is developed using [MetaCall Core] itself in order to provide polyglot support, we are using its [Node Port](https://github.com/metacall/core/tree/develop/source/ports/node_port) of this library to use all the functions and methods `MetaCall Core C API` provides.

- Also, [Here](https://github.com/metacall/faas/blob/master/types/metacall.d.ts) are all the functions of `MetaCall Core` we are using.
16 changes: 9 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
"description": "Reimplementation of MetaCall FaaS platform written in TypeScript.",
"main": "dist/server.js",
"scripts": {
"test": "npm run --silent build && mocha dist/test",
"unit": "npm run --silent test -- --ignore **/integration**",
"prepublishOnly": "npm run --silent build",
"build": "npm run --silent lint && tsc",
"test": "npm run build && mocha dist/test",
"unit": "npm run test -- --ignore **/integration**",
"prepublishOnly": "npm run build",
"build": "npm run lint && tsc",
"lint": "eslint . --max-warnings=0 --ignore-pattern dist",
"fix": "eslint . --max-warnings=0 --ignore-pattern dist --fix",
"start": "npm run build && metacall dist/server.js"
Expand Down Expand Up @@ -89,6 +89,7 @@
"@types/busboy": "^1.3.0",
"@types/express": "^4.17.15",
"@types/git-clone": "^0.2.0",
"@types/node": "^14.14.7",
"@types/unzipper": "^0.10.5",
"@typescript-eslint/eslint-plugin": "^4.7.0",
"@typescript-eslint/parser": "^4.7.0",
Expand All @@ -100,4 +101,4 @@
"prettier": "^2.1.2",
"typescript": "^4.3.2"
}
}
}
38 changes: 21 additions & 17 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ import deployDeleteController from './controller/delete';
import uploadController from './controller/upload';

import {
CurrentUploadedFile,
ProtocolMessageType,
WorkerMessage,
WorkerMessageUnknown,
allApplications,
childProcessResponse,
childProcesses,
currentFile,
deleteBody,
deployBody,
fetchBranchListBody,
fetchFilesFromRepoBody,
protocol
fetchFilesFromRepoBody
} from './constants';

import AppError from './utils/appError';
Expand Down Expand Up @@ -68,19 +70,19 @@ export const callFnByName = (
let errorCame = false;

childProcesses[app].send({
type: protocol.c,
fn: {
type: ProtocolMessageType.Invoke,
data: {
name,
args
}
});

childProcesses[app].on('message', (data: childProcessResponse) => {
childProcesses[app].on('message', (message: WorkerMessageUnknown) => {
if (!responseSent) {
// Check if response has already been sent
if (data.type === protocol.r) {
if (message.type === ProtocolMessageType.InvokeResult) {
responseSent = true; // Set flag to true to indicate response has been sent
return res.send(JSON.stringify(data.data));
return res.send(JSON.stringify(message.data));
} else {
errorCame = true;
}
Expand Down Expand Up @@ -141,7 +143,7 @@ export const fetchFilesFromRepo = catchAsync(
await ensureFolderExists(appsDir);

try {
deleteRepoFolderIfExist(appsDir, url);
await deleteRepoFolderIfExist(appsDir, url);
} catch (err) {
next(
new AppError(
Expand Down Expand Up @@ -196,7 +198,7 @@ export const fetchFileList = catchAsync(
await ensureFolderExists(appsDir);

try {
deleteRepoFolderIfExist(appsDir, req.body.url);
await deleteRepoFolderIfExist(appsDir, req.body.url);
} catch (err) {
next(
new AppError(
Expand Down Expand Up @@ -242,19 +244,21 @@ export const deploy = catchAsync(
});

proc.send({
type: protocol.l,
currentFile
type: ProtocolMessageType.Load,
data: currentFile
});

logProcessOutput(proc.stdout, proc.pid, currentFile.id);
logProcessOutput(proc.stderr, proc.pid, currentFile.id);

proc.on('message', (data: childProcessResponse) => {
if (data.type === protocol.g) {
if (isIAllApps(data.data)) {
const appName = Object.keys(data.data)[0];
proc.on('message', (payload: WorkerMessageUnknown) => {
if (payload.type === ProtocolMessageType.MetaData) {
const message =
payload as WorkerMessage<CurrentUploadedFile>;
if (isIAllApps(message.data)) {
const appName = Object.keys(message.data)[0];
childProcesses[appName] = proc;
allApplications[appName] = data.data[appName];
allApplications[appName] = message.data[appName];
}
}
});
Expand Down
11 changes: 0 additions & 11 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import express, { NextFunction, Request, Response } from 'express';
import * as api from './api';
import { allApplications } from './constants';
import AppError from './utils/appError';
import { findJsonFilesRecursively } from './utils/autoDeploy';
import { appsDirectory } from './utils/config';
import globalErrorHandler from './utils/errorHandler';

const app = express();
Expand Down Expand Up @@ -44,15 +42,6 @@ app.all('*', (req: Request, res: Response, next: NextFunction) => {
next(new AppError(`Can't find ${req.originalUrl} on this server!`, 404));
});

const appsDir = appsDirectory();
findJsonFilesRecursively(appsDir)
.then(() => {
console.log('Previously deployed apllications deployed successfully');
})
.catch(error => {
console.error('Error while re-deploying applications', error);
});

app.use(globalErrorHandler);

export default app;
26 changes: 14 additions & 12 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { DeployStatus, MetaCallJSON } from '@metacall/protocol/deployment';
import { ChildProcess } from 'child_process';

export interface currentUploadedFile {
export interface CurrentUploadedFile {
id: string;
type?: string;
jsons: MetaCallJSON[];
runners?: string[];
path: string;
}

export const currentFile: currentUploadedFile = {
export const currentFile: CurrentUploadedFile = {
id: '',
type: '',
jsons: [],
Expand Down Expand Up @@ -100,21 +100,23 @@ export type IAllApps = Record<string, IAppWithFunctions>;

export const allApplications: IAllApps = {};

export const protocol = {
i: 'installDependencies',
l: 'loadFunctions',
g: 'getApplicationMetadata',
c: 'callFunction',
r: 'functionInvokeResult'
};
export enum ProtocolMessageType {
Install = 'InstallDependencies',
Load = 'LoadFunctions',
MetaData = 'GetApplicationMetadata',
Invoke = 'CallFunction',
InvokeResult = 'FunctionInvokeResult'
}

export const childProcesses: { [key: string]: ChildProcess } = {};

export interface childProcessResponse {
type: keyof typeof protocol;
data: unknown;
export interface WorkerMessage<T> {
type: ProtocolMessageType;
data: T;
}

export type WorkerMessageUnknown = WorkerMessage<unknown>;

export interface InspectObject {
[key: string]: Array<{ name: string }>;
}
Expand Down
28 changes: 23 additions & 5 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
import * as dotenv from 'dotenv';

import app from './app';
import { findJsonFilesRecursively } from './utils/autoDeploy';
import { appsDirectory } from './utils/config';
import { ensureFolderExists } from './utils/utils';

dotenv.config();
// Initialize the FaaS
void (async (): Promise<void> => {
try {
dotenv.config();

const port = process.env.PORT || 9000;
const appsDir = appsDirectory();

app.listen(port, () => {
console.log(`Server is running on the port ${port}`);
});
await ensureFolderExists(appsDir);

await findJsonFilesRecursively(appsDir);

console.log('Previously deployed apllications deployed successfully');

const port = process.env.PORT || 9000;

app.listen(port, () => {
console.log(`Server is running on the port ${port}`);
});
} catch (e) {
console.error('Error while re-deploying applications: ', e);
}
})();
32 changes: 20 additions & 12 deletions src/utils/autoDeploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ import { spawn } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import {
CurrentUploadedFile,
IAppWithFunctions,
ProtocolMessageType,
WorkerMessage,
WorkerMessageUnknown,
allApplications,
childProcessResponse,
childProcesses,
currentFile,
protocol
currentFile
} from '../constants';
import { isIAllApps, logProcessOutput } from './utils';

Expand All @@ -31,20 +34,25 @@ export const findJsonFilesRecursively = async (
stdio: ['pipe', 'pipe', 'pipe', 'ipc']
});

proc.send({
type: protocol.l,
currentFile
});
const message: WorkerMessage<CurrentUploadedFile> = {
type: ProtocolMessageType.Load,
data: currentFile
};

proc.send(message);

logProcessOutput(proc.stdout, proc.pid, currentFile.id);
logProcessOutput(proc.stderr, proc.pid, currentFile.id);

proc.on('message', (data: childProcessResponse) => {
if (data.type === protocol.g) {
if (isIAllApps(data.data)) {
const appName = Object.keys(data.data)[0];
proc.on('message', (payload: WorkerMessageUnknown) => {
if (payload.type === ProtocolMessageType.MetaData) {
const message = payload as WorkerMessage<
Record<string, IAppWithFunctions>
>;
if (isIAllApps(message.data)) {
const appName = Object.keys(message.data)[0];
childProcesses[appName] = proc;
allApplications[appName] = data.data[appName];
allApplications[appName] = message.data[appName];
}
}
});
Expand Down
Loading

0 comments on commit a9b1dea

Please sign in to comment.