diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ceed98b..cba0ab7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,8 +24,13 @@ jobs: uses: thebongy/version-check@v1 with: file: package.json + failBuild: false id: version_check + - name: Bump package.json version (staging) + if: github.ref == 'refs/heads/staging' + run: npm -no-git-tag-version version v${{ steps.version_check.outputs.rawVersion }}-beta + - name: Install dependencies run: npm ci @@ -36,12 +41,18 @@ jobs: run: npm run build - name: Create tarball - run: npm pack + run: | + npm pack + + - name: Rename tar (staging) + if: github.ref == 'refs/heads/staging' + run: mv *.tgz juno-node-${{ steps.version_check.outputs.rawVersion }}.tgz + - name: Upload Artifact uses: actions/upload-artifact@v2 with: - name: juno-node-${{ steps.version_check.outputs.releaseVersion }} + name: juno-node-${{ steps.version_check.outputs.rawVersion }} path: ./juno-node-${{ steps.version_check.outputs.rawVersion }}.tgz # Publish release on push to master @@ -71,7 +82,7 @@ jobs: uses: actions/create-release@latest with: tag_name: ${{ steps.version_check.outputs.releaseVersion }} - release_name: juno-node-${{ steps.version_check.outputs.releaseVersion }} + release_name: ${{ steps.version_check.outputs.releaseVersion }} prerelease: false env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -120,14 +131,14 @@ jobs: - name: Download Artifact uses: actions/download-artifact@v2 with: - name: juno-node-${{ steps.version_check.outputs.releaseVersion }} + name: juno-node-${{ steps.version_check.outputs.rawVersion }} - name: Publish Release id: create_release uses: actions/create-release@latest with: tag_name: ${{ steps.version_check.outputs.releaseVersion }} - release_name: juno-node-${{ steps.version_check.outputs.releaseVersion }} + release_name: ${{ steps.version_check.outputs.releaseVersion }} prerelease: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/package.json b/package.json index 85fd719..84df1a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "juno-node", - "version": "0.0.3", + "version": "0.1.1", "description": "", "keywords": [], "main": "dist/juno-node.cjs.js", @@ -12,7 +12,7 @@ "author": "thebongy ", "repository": { "type": "git", - "url": "" + "url": "https://github.com/bytesonus/juno-node" }, "license": "MIT", "engines": { diff --git a/src/connection/inet-socket-connection.ts b/src/connection/inet-socket-connection.ts new file mode 100644 index 0000000..08d1521 --- /dev/null +++ b/src/connection/inet-socket-connection.ts @@ -0,0 +1,43 @@ +import { Socket, createConnection } from 'net'; +import BaseConnection from './base-connection'; + +export default class InetSocketConnection extends BaseConnection { + client?: Socket; + host: string; + port: number; + + constructor(host: string, port: number) { + super(); + this.host = host; + this.port = port; + } + + setupConnection(): Promise { + return new Promise(resolve => { + this.client = createConnection(this.port, this.host); + this.client.on('data', (data) => { + const dataLines = data.toString().split(/\r?\n/); + dataLines.map((data) => { + if (data) { + this.onData(Buffer.from(data)) + } + }); + }); + this.client.on('connect', () => { + resolve(); + }); + }); + } + + async closeConnection() { + this.client?.destroy(); + } + + send(message: Buffer): Promise { + return new Promise(resolve => { + this.client?.write(message, () => { + resolve(); + }); + }); + } +} diff --git a/src/connection/unix-socket-connection.ts b/src/connection/unix-socket-connection.ts index e6a0735..f94800d 100644 --- a/src/connection/unix-socket-connection.ts +++ b/src/connection/unix-socket-connection.ts @@ -1,8 +1,8 @@ -import * as net from 'net'; +import { Socket, createConnection } from 'net'; import BaseConnection from './base-connection'; -export default class SocketConnection extends BaseConnection { - client?: net.Socket; +export default class UnixSocketConnection extends BaseConnection { + client?: Socket; sockPath: string; constructor(sockPath: string) { @@ -12,7 +12,7 @@ export default class SocketConnection extends BaseConnection { setupConnection(): Promise { return new Promise(resolve => { - this.client = net.createConnection(this.sockPath); + this.client = createConnection(this.sockPath); this.client.on('data', (data) => { const dataLines = data.toString().split(/\r?\n/); dataLines.map((data) => { diff --git a/src/juno-node.ts b/src/juno-node.ts index 14d9825..0fe0f43 100644 --- a/src/juno-node.ts +++ b/src/juno-node.ts @@ -1,3 +1,5 @@ +import { isIP } from 'net'; +import { promises as fsPromises } from 'fs'; import { BaseProtocol } from './protocol/base-protocol'; import BaseConnection from './connection/base-connection'; import { JsonProtocol } from './protocol/json-protocol'; @@ -8,7 +10,8 @@ import { TriggerHookRequest, JunoMessage } from './models/messages'; -import SocketConnection from './connection/unix-socket-connection'; +import UnixSocketConnection from './connection/unix-socket-connection'; +import InetSocketConnection from './connection/inet-socket-connection'; export default class JunoModule { @@ -27,8 +30,38 @@ export default class JunoModule { // this.connection.setOnDataListener(this.onDataHandler); } - public static default(socketPath: string): JunoModule { - return new JunoModule(new SocketConnection(socketPath), new JsonProtocol()); + public static async default(socketPath: string) { + const [ host, port ] = socketPath.split(':'); + + if (isIP(host) && !isNaN(Number(port))) { + return this.fromInetSocket(host, Number(port)); + } + if ( (await fsPromises.lstat(socketPath)).isSocket() ) { + return this.fromUnixSocket(socketPath); + } + + throw new Error('Invalid socket object. Only unix domain sockets and Inet sockets are allowed'); + + } + + public static async fromUnixSocket(path: string) { + // Return Error if invoked from windows + if (process.platform == 'win32') { + throw new Error('Unix sockets are not supported on windows'); + } + if ( (await fsPromises.lstat(path)).isSocket() ) { + return new JunoModule(new UnixSocketConnection(path), new JsonProtocol()); + } + + throw new Error('Invalid unix socket path'); + } + + public static async fromInetSocket(host: string, port: number) { + if (isIP(host) && !isNaN(Number(port))) { + return new JunoModule(new InetSocketConnection(host, port), new JsonProtocol()); + } + + throw new Error('Invalid Inet socket address. Use the format `{host}:{port}`') } public async initialize( @@ -77,9 +110,9 @@ export default class JunoModule { ); } - public async triggerHook(hook: string) { + public async triggerHook(hook: string, data: any = {}) { return this.sendRequest( - this.protocol.triggerHook(hook) + this.protocol.triggerHook(hook, data) ); } @@ -125,7 +158,7 @@ export default class JunoModule { break; } case ResponseTypes.FunctionResponse: { - value = await (response as FunctionCallResponse).data; + value = (response as FunctionCallResponse).data; break; } case ResponseTypes.FunctionDeclared: { @@ -186,7 +219,7 @@ export default class JunoModule { } } else if (this.hookListeners[request.hook]) { for (const listener of this.hookListeners[request.hook]) { - listener(); + listener(request.data || {}); } } return true; diff --git a/src/models/messages.ts b/src/models/messages.ts index 351df5a..3cfddf4 100644 --- a/src/models/messages.ts +++ b/src/models/messages.ts @@ -28,6 +28,9 @@ export interface RegisterHookRequest extends BaseMessage { export interface TriggerHookRequest extends BaseMessage { hook: string; + data: { + [type: string]: any + }; } export interface RegisterModuleResponse extends BaseMessage { @@ -43,7 +46,6 @@ export interface ListenHookResponse extends BaseMessage { export interface TriggerHookResponse extends BaseMessage { hook: string; - data?: any; } export interface DeclareFunctionResponse extends BaseMessage { diff --git a/src/protocol/base-protocol.ts b/src/protocol/base-protocol.ts index b6452dc..cc5c437 100644 --- a/src/protocol/base-protocol.ts +++ b/src/protocol/base-protocol.ts @@ -42,11 +42,12 @@ export abstract class BaseProtocol { }; } - public triggerHook(hook: string): TriggerHookRequest { + public triggerHook(hook: string, data: any): TriggerHookRequest { return { requestId: this.generateRequestId(), type: RequestTypes.TriggerHook, - hook + hook, + data }; } diff --git a/test/juno-node.test.ts b/test/juno-node.test.ts index 501b304..609dc36 100644 --- a/test/juno-node.test.ts +++ b/test/juno-node.test.ts @@ -106,12 +106,29 @@ makeConnectionTests('Test if requests constructed correctly', function () { }); }); - it('triggerHook', function () { + it('triggerHook with no args', function () { this.test.module.triggerHook('test_hook'); const message = this.test.getLatestSent(); expect(message).excluding('requestId').to.deep.equal({ type: 7, hook: 'test_hook', + data: {}, + }); + }); + + it('triggerHook with args', function () { + this.test.module.triggerHook('test_hook', { + a:1, + b:2, + }); + const message = this.test.getLatestSent(); + expect(message).excluding('requestId').to.deep.equal({ + type: 7, + hook: 'test_hook', + data: { + a: 1, + b: 2, + } }); }); });