Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create node for BlueIris api #2555

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions packages/nodes-base/credentials/BlueIrisApi.credentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {
ICredentialType,
INodeProperties,
} from 'n8n-workflow';

export class BlueIrisApi implements ICredentialType {
name = 'blueIrisApi';
displayName = 'BlueIris Api';
documentationUrl = 'BlueIris';
properties: INodeProperties[] = [
{
displayName: 'Username',
name: 'username',
type: 'string',
default: '',
},
{
displayName: 'Password',
name: 'password',
type: 'string',
typeOptions: {
password: true,
},
default: '',
},
];
}
90 changes: 90 additions & 0 deletions packages/nodes-base/nodes/BlueIris/BlueIris.node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import {
IExecuteFunctions,
} from 'n8n-core';

import {
IDataObject,
INodeExecutionData,
INodeType,
INodeTypeDescription,
} from 'n8n-workflow';

import { performOperation } from './GenericFunctions';

export class BlueIris implements INodeType {
description: INodeTypeDescription = {
displayName: 'BlueIris',
name: 'BlueIris',
icon: 'file:BlueIris.png',
group: ['input'],
version: 1,
description: 'Node to consume BlueIris API',
defaults: {
name: 'BlueIris',
color: '#517db7',
},
inputs: ['main'],
outputs: ['main'],
credentials: [
{
name: 'blueIrisApi',
required: true,
},
],
properties: [
{
displayName: 'API URL',
name: 'apiUrl',
type: 'string',
required: true,
description: 'The URL of the API. For example https://yourdomain:81/json',
default: '',
},
{
displayName: 'Operation',
name: 'operation',
type: 'options',
default: 'status',
required: true,
description: 'Operation to perform. Currently only some read operation are supported',
options: [
{
name: 'Status',
value: 'status',
description: 'Get (and optionally set) the state of the shield, active global profile as well as the schedule\'shold/run state and other system vitals',
},
{
name: 'Cameras List',
value: 'camlist',
description: 'Returns a list of cameras on the system ordered by group. Cameras not belonging to any' +
'group are shown beneath the \"all cameras\" group. Disabled cameras are placed at the end of' +
'the list.',
},
],
},
],
};

async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
const returnData: IDataObject[] = [];
const items = this.getInputData();
const length = items.length as unknown as number;

for (let i = 0; i < length; i++) {
try {
const apiUrl = this.getNodeParameter('apiUrl', i) as string;
const responseData = await performOperation.call(this, apiUrl);
returnData.push(responseData);
} catch (error) {
if (this.continueOnFail()) {
returnData.push({ error: error.description });
} else {
throw error;
}
}
}

return [this.helpers.returnJsonArray(returnData)];
}

}
Binary file added packages/nodes-base/nodes/BlueIris/BlueIris.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
97 changes: 97 additions & 0 deletions packages/nodes-base/nodes/BlueIris/GenericFunctions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {
OptionsWithUri,
} from 'request';

import {
IExecuteFunctions,
IExecuteSingleFunctions,
IHookFunctions,
ILoadOptionsFunctions,
} from 'n8n-core';

import { INode, NodeOperationError } from 'n8n-workflow';
import { createHash } from 'crypto';

export async function performOperation(this: IHookFunctions | IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, apiUrl: string): Promise<any> { // tslint:disable-line:no-any
const credentials = await this.getCredentials('blueIrisApi');
if (!credentials) {
throw new NodeOperationError(this.getNode(), 'Credentials are mandatory!');
}
const operation = this.getNodeParameter('operation', 0) as string;

const initSessionRequest = getInitializeSessionRequest(apiUrl);
let responseData = await this.helpers.request!(initSessionRequest);

const session = responseData.session;
const authenticatioRequest = `${credentials.username}:${session}:${credentials.password}`;
const hashedAuthentication = createHash('md5').update(authenticatioRequest).digest('hex');

const loginRequest = getLoginRequest(apiUrl, session, hashedAuthentication);
responseData = await this.helpers.request!(loginRequest);
checkResponseErrors(this.getNode(), responseData);

const operationRequest = getOperationRequest(apiUrl, session, operation);
responseData = await this.helpers.request!(operationRequest);
checkResponseErrors(this.getNode(), responseData);

const logoutRequest = getCloseSessionRequest(apiUrl, session);
await this.helpers.request!(logoutRequest);

return responseData;
}

function checkResponseErrors(node: INode, responseData: any) { // tslint:disable-line:no-any
if (responseData.result !== 'success') {
throw new NodeOperationError(node, `Received the following error from BlueIris API: ${responseData.data.reason}`);
}
}

function getInitializeSessionRequest(apiUrl: string) {
const body = { cmd: 'login' };
return {
body,
method: 'POST',
uri: apiUrl,
json: true,
} as OptionsWithUri;
}

function getLoginRequest(apiUrl: string, session: string, hashedAuthentication: string) {
const body = {
cmd: 'login',
session,
response: hashedAuthentication,
};
return {
body,
method: 'POST',
uri: apiUrl,
json: true,
} as OptionsWithUri;
}

function getOperationRequest(apiUrl: string, session: string, operation: string) {
const body = {
cmd: operation,
session,
};
return {
body,
method: 'POST',
uri: apiUrl,
json: true,
} as OptionsWithUri;
}

function getCloseSessionRequest(apiUrl: string, session: string) {
const body = {
cmd: 'logout',
session,
};
return {
body,
method: 'POST',
uri: apiUrl,
json: true,
} as OptionsWithUri;
}
6 changes: 4 additions & 2 deletions packages/nodes-base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@
"dist/credentials/ZohoOAuth2Api.credentials.js",
"dist/credentials/ZoomApi.credentials.js",
"dist/credentials/ZoomOAuth2Api.credentials.js",
"dist/credentials/ZulipApi.credentials.js"
"dist/credentials/ZulipApi.credentials.js",
"dist/credentials/BlueIrisApi.credentials.js"
],
"nodes": [
"dist/nodes/ActionNetwork/ActionNetwork.node.js",
Expand Down Expand Up @@ -648,7 +649,8 @@
"dist/nodes/Zendesk/ZendeskTrigger.node.js",
"dist/nodes/Zoho/ZohoCrm.node.js",
"dist/nodes/Zoom/Zoom.node.js",
"dist/nodes/Zulip/Zulip.node.js"
"dist/nodes/Zulip/Zulip.node.js",
"dist/nodes/BlueIris/BlueIris.node.js"
]
},
"devDependencies": {
Expand Down