first-fix

This commit is contained in:
Alexander Abakumov committed 2024-06-23 23:04:49 +03:00
1 parent 6d87c1edc8
commit 565d9d673a
6284 files changed
+820267 -76

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
*.toDelete
output/**
*.class
*~
*.iml
*/.idea/**
.idea/**
.idea
*.log
*.log.[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]
*/.classpath
.classpath
*/.project
.project
.cache/**
target/
logs/
build/
.settings/
/bin
bin/
**/dependency-reduced-pom.xml
pom.xml.versionsBackup
.DS_Store
**/.gradle
**/local.properties
**/build
**/target
**/.env
node_modules
@@ -0,0 +1,31 @@
#
# Copyright © 2016-2023 The Thingsboard Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
server:
# Server bind address
address: "HTTP_BIND_ADDRESS"
# Server bind port
port: "HTTP_BIND_PORT"
thingsboard:
enableProxy: "TB_ENABLE_PROXY"
# ThingsBoard node host
host: "TB_HOST"
# ThingsBoard node port
port: "TB_PORT"
logger:
level: "LOGGER_LEVEL"
path: "LOG_FOLDER"
filename: "LOGGER_FILENAME"
+31
View File
@@ -0,0 +1,31 @@
#
# Copyright © 2016-2023 The Thingsboard Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
server:
# Server bind address
address: "0.0.0.0"
# Server bind port
port: "8090"
thingsboard:
enableProxy: "false"
# ThingsBoard node host
host: "localhost"
# ThingsBoard node port
port: "8080"
logger:
level: "info"
path: "logs"
filename: "tb-web-ui-%DATE%.log"
+63
View File
@@ -0,0 +1,63 @@
///
/// Copyright © 2016-2023 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import config from 'config';
import path from 'path';
import DailyRotateFile from 'winston-daily-rotate-file';
import { createLogger, format, transports } from 'winston';
import * as Transport from 'winston-transport';
const { combine, timestamp, label, printf, splat } = format;
const loggerTransports: Array<Transport> = [];
if (process.env.NODE_ENV !== 'production' || process.env.DOCKER_MODE === 'true') {
loggerTransports.push(new transports.Console({
handleExceptions: true
}));
} else {
const filename = path.join(config.get('logger.path'), config.get('logger.filename'));
const transport = new (DailyRotateFile)({
filename: filename,
datePattern: 'YYYY-MM-DD-HH',
zippedArchive: true,
maxSize: '20m',
maxFiles: '14d',
handleExceptions: true
});
loggerTransports.push(transport);
}
const tbFormat = printf(info => {
let logMessage = `${info.timestamp} [${info.label}] ${info.level.toUpperCase()}: ${info.message}`;
if (info.stack) {
logMessage += ':\n' + info.stack;
}
return logMessage;
});
export function _logger(moduleLabel: string) {
return createLogger({
level: config.get('logger.level'),
format:combine(
splat(),
label({ label: moduleLabel }),
timestamp({format: 'YYYY-MM-DD HH:mm:ss,SSS'}),
tbFormat
),
transports: loggerTransports
});
}
+20
View File
@@ -0,0 +1,20 @@
#
# Copyright © 2016-2023 The Thingsboard Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
export NODE_CONFIG_DIR=${pkg.installFolder}/conf
export LOG_FOLDER=${pkg.logFolder}
export NODE_ENV=production
export WEB_FOLDER=${pkg.installFolder}/web
+41
View File
@@ -0,0 +1,41 @@
#
# Copyright © 2016-2023 The Thingsboard Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
FROM thingsboard/node:16.17.0-bullseye-slim
ENV NODE_ENV production
ENV DOCKER_MODE true
COPY start-web-ui.sh /tmp/
WORKDIR ${pkg.installFolder}
COPY ["src/package.json", "src/yarn.lock", "./"]
COPY package/linux/conf ./conf
COPY package/linux/conf ./config
COPY web ./web
COPY src/config ./config
COPY src/server.js ./
RUN chmod a+x /tmp/*.sh \
&& mv /tmp/start-web-ui.sh /usr/bin \
&& chown -R node:node ${pkg.installFolder} \
&& yarn install --production && yarn cache clean --all
USER node
CMD ["start-web-ui.sh"]
+30
View File
@@ -0,0 +1,30 @@
#!/bin/bash
#
# Copyright © 2016-2023 The Thingsboard Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
echo "Starting '${project.name}' ..."
CONF_FOLDER="${pkg.installFolder}/conf"
configfile=${pkg.name}.conf
source "${CONF_FOLDER}/${configfile}"
cd ${pkg.installFolder}
# This will forward this PID 1 to the node.js and forward SIGTERM for graceful shutdown as well
exec node server.js
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright © 2016-2023 The Thingsboard Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const fs = require('fs');
const fse = require('fs-extra');
const path = require('path');
let _projectRoot = null;
(async() => {
await fse.move(path.join(projectRoot(), 'target', 'thingsboard-web-ui-linux'),
path.join(targetPackageDir('linux'), 'bin', 'tb-web-ui'),
{overwrite: true});
await fse.move(path.join(projectRoot(), 'target', 'thingsboard-web-ui-win.exe'),
path.join(targetPackageDir('windows'), 'bin', 'tb-web-ui.exe'),
{overwrite: true});
})();
function projectRoot() {
if (!_projectRoot) {
_projectRoot = __dirname;
}
return _projectRoot;
}
function targetPackageDir(platform) {
return path.join(projectRoot(), 'target', 'package', platform);
}
+57
View File
@@ -0,0 +1,57 @@
{
"name": "thingsboard-web-ui",
"private": true,
"version": "3.5.2",
"description": "ThingsBoard Web UI Microservice",
"main": "server.ts",
"bin": "server.js",
"scripts": {
"pkg": "tsc && pkg -t node16-linux-x64,node16-win-x64 --out-path ./target ./target/src && node install.js",
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon --watch '.' --ext 'ts' --exec 'WEB_FOLDER=./target/web ts-node server.ts'",
"start-prod": "nodemon --watch '.' --ext 'ts' --exec 'WEB_FOLDER=./target/web NODE_ENV=production ts-node server.ts'",
"build": "tsc"
},
"dependencies": {
"compression": "^1.7.4",
"config": "^3.3.7",
"connect-history-api-fallback": "^1.6.0",
"express": "^4.18.1",
"http": "0.0.0",
"http-proxy": "^1.18.1",
"js-yaml": "^4.1.0",
"winston": "^3.7.2",
"winston-daily-rotate-file": "^4.7.1"
},
"nyc": {
"exclude": [
"test",
"__tests__",
"node_modules",
"target"
]
},
"devDependencies": {
"@types/compression": "^1.7.2",
"@types/config": "^0.0.41",
"@types/connect-history-api-fallback": "^1.3.5",
"@types/express": "^4.17.13",
"@types/http-proxy": "^1.17.9",
"@types/node": "^18.0.0",
"fs-extra": "^10.1.0",
"nodemon": "^2.0.16",
"pkg": "^5.7.0",
"ts-node": "^10.8.1",
"typescript": "^4.7.4"
},
"pkg": {
"assets": [
"node_modules/config/**/*.*"
]
},
"resolutions": {
"color-string": "^1.5.5",
"follow-redirects": "^1.14.8",
"minimist": "^1.2.6"
}
}
+301
View File
@@ -0,0 +1,301 @@
<!--
Copyright © 2016-2023 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.thingsboard</groupId>
<version>0.6.2-SNAPSHOT</version>
<artifactId>msa</artifactId>
</parent>
<groupId>org.thingsboard.msa</groupId>
<artifactId>web-ui</artifactId>
<packaging>pom</packaging>
<name>ThingsBoard Web UI Microservice</name>
<url>https://thingsboard.io</url>
<description>Service for hosting ThingsBoard Web UI</description>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<main.dir>${basedir}/../..</main.dir>
<pkg.name>tb-web-ui</pkg.name>
<pkg.type>js</pkg.type>
<docker.name>tb-web-ui</docker.name>
<pkg.name>tb-web-ui</pkg.name>
<pkg.type>js</pkg.type>
<pkg.disabled>false</pkg.disabled>
<pkg.process-resources.phase>process-resources</pkg.process-resources.phase>
<pkg.package.phase>package</pkg.package.phase>
<pkg.linux.dist>${project.build.directory}/package/linux</pkg.linux.dist>
<pkg.win.dist>${project.build.directory}/package/windows</pkg.win.dist>
<docker.push-arm-amd-image.phase>pre-integration-test</docker.push-arm-amd-image.phase>
</properties>
<dependencies>
<dependency>
<groupId>org.thingsboard</groupId>
<artifactId>ui-ngx</artifactId>
<version>${project.version}</version>
<type>jar</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.sun.winsw</groupId>
<artifactId>winsw</artifactId>
<classifier>bin</classifier>
<type>exe</type>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<configuration>
<installDirectory>target</installDirectory>
<workingDirectory>${basedir}</workingDirectory>
</configuration>
<executions>
<execution>
<id>install node and yarn</id>
<goals>
<goal>install-node-and-yarn</goal>
</goals>
<configuration>
<nodeVersion>v16.15.1</nodeVersion>
<yarnVersion>v1.22.17</yarnVersion>
</configuration>
</execution>
<execution>
<id>yarn install</id>
<goals>
<goal>yarn</goal>
</goals>
<configuration>
<arguments>install</arguments>
</configuration>
</execution>
<execution>
<id>yarn pkg</id>
<goals>
<goal>yarn</goal>
</goals>
<phase>compile</phase>
<configuration>
<arguments>run pkg</arguments>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>extract-web-ui</id>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.thingsboard</groupId>
<artifactId>ui-ngx</artifactId>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${project.build.directory}/web</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
<execution>
<id>copy-winsw-service</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>com.sun.winsw</groupId>
<artifactId>winsw</artifactId>
<classifier>bin</classifier>
<type>exe</type>
<destFileName>service.exe</destFileName>
</artifactItem>
</artifactItems>
<outputDirectory>${pkg.win.dist}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-src-root</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/src</outputDirectory>
<resources>
<resource>
<directory>${basedir}</directory>
<includes>
<include>package.json</include>
<include>yarn.lock</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.thingsboard</groupId>
<artifactId>gradle-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<executions>
<execution>
<id>build-docker-image</id>
<phase>pre-integration-test</phase>
<goals>
<goal>build</goal>
</goals>
<configuration>
<skip>${dockerfile.skip}</skip>
<repository>${docker.repo}/${docker.name}</repository>
<verbose>true</verbose>
<googleContainerRegistryEnabled>false</googleContainerRegistryEnabled>
<contextDirectory>${project.build.directory}</contextDirectory>
</configuration>
</execution>
<execution>
<id>tag-docker-image</id>
<phase>pre-integration-test</phase>
<goals>
<goal>tag</goal>
</goals>
<configuration>
<skip>${dockerfile.skip}</skip>
<repository>${docker.repo}/${docker.name}</repository>
<tag>${project.version}</tag>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>yarn-start</id>
<activation>
<property>
<name>yarn-start</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<configuration>
<installDirectory>target</installDirectory>
<workingDirectory>${basedir}</workingDirectory>
</configuration>
<executions>
<execution>
<id>yarn start</id>
<goals>
<goal>yarn</goal>
</goals>
<configuration>
<arguments>start</arguments>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>push-docker-image</id>
<activation>
<property>
<name>push-docker-image</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<executions>
<execution>
<id>push-latest-docker-image</id>
<phase>pre-integration-test</phase>
<goals>
<goal>push</goal>
</goals>
<configuration>
<tag>latest</tag>
<repository>${docker.repo}/${docker.name}</repository>
</configuration>
</execution>
<execution>
<id>push-version-docker-image</id>
<phase>pre-integration-test</phase>
<goals>
<goal>push</goal>
</goals>
<configuration>
<tag>${project.version}</tag>
<repository>${docker.repo}/${docker.name}</repository>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<repositories>
<repository>
<id>jenkins</id>
<name>Jenkins Repository</name>
<url>https://repo.jenkins-ci.org/releases</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
+154
View File
@@ -0,0 +1,154 @@
///
/// Copyright © 2016-2023 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import express from 'express';
import config from 'config';
import { _logger} from './config/logger';
import path from 'path';
import http, { ServerResponse } from 'http';
import httpProxy from 'http-proxy';
import compression from 'compression';
import historyApiFallback from 'connect-history-api-fallback';
import { Socket } from 'net';
const logger = _logger('main');
let server: http.Server | null;
let connections: Socket[] = [];
(async() => {
try {
logger.info('Starting ThingsBoard Web UI Microservice...');
const bindAddress: string = config.get('server.address');
const bindPort = Number(config.get('server.port'));
const thingsboardEnableProxy: string = config.get('thingsboard.enableProxy');
const thingsboardHost: string = config.get('thingsboard.host');
const thingsboardPort = Number(config.get('thingsboard.port'));
logger.info('Bind address: %s', bindAddress);
logger.info('Bind port: %s', bindPort);
logger.info('ThingsBoard Enable Proxy: %s', thingsboardEnableProxy);
logger.info('ThingsBoard host: %s', thingsboardHost);
logger.info('ThingsBoard port: %s', thingsboardPort);
const useApiProxy = thingsboardEnableProxy === "true";
let webDir = path.join(__dirname, 'web');
if (typeof process.env.WEB_FOLDER !== 'undefined') {
webDir = path.resolve(process.env.WEB_FOLDER);
}
logger.info('Web folder: %s', webDir);
const app = express();
server = http.createServer(app);
let apiProxy: httpProxy;
if (useApiProxy) {
apiProxy = httpProxy.createProxyServer({
target: {
host: thingsboardHost,
port: thingsboardPort
}
});
apiProxy.on('error', (err, req, res) => {
logger.warn('API proxy error: %s', err.message);
if (res instanceof ServerResponse) {
res.writeHead(500);
const error = err as any;
if (error.code && error.code === 'ECONNREFUSED') {
res.end('Unable to connect to ThingsBoard server.');
} else {
res.end('ThingsBoard server connection error: ' + error.code ? error.code : '');
}
}
});
app.all('/api/*', (req, res) => {
logger.debug(req.method + ' ' + req.originalUrl);
apiProxy.web(req, res);
});
app.all('/static/rulenode/*', (req, res) => {
apiProxy.web(req, res);
});
server.on('upgrade', (req, socket, head) => {
apiProxy.ws(req, socket, head);
});
}
app.use(historyApiFallback());
app.use(compression());
const root = path.join(webDir, 'public');
app.use(express.static(root));
server.listen(bindPort, bindAddress, () => {
logger.info('==> 🌎 Listening on port %s.', bindPort);
logger.info('Started ThingsBoard Web UI Microservice.');
}).on('error', async (error) => {
logger.error('Failed to start ThingsBoard Web UI Microservice: %s', error.message);
logger.error(error.stack);
await exit(-1);
});
server.on('connection', connection => {
connections.push(connection);
connection.on('close', () => connections = connections.filter(curr => curr !== connection));
});
} catch (e: any) {
logger.error('Failed to start ThingsBoard Web UI Microservice: %s', e.message);
logger.error(e.stack);
await exit(-1);
}
})();
[`SIGINT`, `SIGUSR1`, `SIGUSR2`, `uncaughtException`, `SIGTERM`].forEach((eventType) => {
process.once(eventType, async () => {
logger.info(`${eventType} signal received`);
await exit(0);
});
})
process.on('exit', async (code: number) => {
logger.info(`ThingsBoard Web UI Microservice has been stopped. Exit code: ${code}.`);
});
async function exit(status: number) {
logger.info('Exiting with status: %d ...', status);
if (server) {
logger.info('Stopping HTTP Server...');
connections.forEach(curr => curr.end(() => curr.destroy()));
const _server = server;
server = null;
const serverClosePromise = new Promise<void>(
(resolve, reject) => {
_server.close((err) => {
logger.info('HTTP Server stopped.');
resolve();
});
}
);
await serverClosePromise;
}
process.exit(status);
}
+13
View File
@@ -0,0 +1,13 @@
{
"compilerOptions": {
"outDir": "target/src",
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"strictPropertyInitialization": false
},
"exclude": ["node_modules", "target"]
}
+2532
View File
File diff suppressed because it is too large. Load diff