Compare commits

..

16 Commits

Author SHA1 Message Date
108000207 d022e72ff1 [update] need to try execute_batch for optimize 2022-08-27 16:51:37 +08:00
108000207 1e82af9ee2 [update] use stream type as api 2022-08-25 16:31:01 +08:00
108000207 327e57e72f [update] api for get_csv, fix bugs for large file 2022-08-24 17:42:53 +08:00
108000207 5d5bf0ee51 [update] differential done 2022-08-23 17:51:21 +08:00
108000207 cf83afc8f3 [update] integral functional done 2022-08-23 17:02:23 +08:00
108000207 c8d0248da1 [update] log functional done 2022-08-23 15:32:00 +08:00
108000207 830fde89a3 [update] support multi "***" and export csv 2022-08-23 13:48:17 +08:00
108000207 fcc76c835c [update] sql get DB and build dataFrame 2022-08-23 11:07:01 +08:00
peterlu14 2937043f78 Merge branch 'feature/project_setting' into release/v1.0.0_project 2022-05-06 10:53:29 +08:00
peterlu14 1f65ad0f11 [update] fix update project 2022-04-29 17:17:03 +08:00
peterlu14 18c61c0996 [update] add new feature project api 2022-04-27 16:10:40 +08:00
peterlu14 451d246952 [update] init_setting 2022-04-15 17:47:39 +08:00
peterlu14 15d6c2cda6 [update] add meta getattrbyparent 2022-04-15 17:47:21 +08:00
peterlu14 5ad6683b81 [update] remove sd_card column 2021-10-19 10:45:30 +08:00
Jordan Hsu a646844b9a Merge branch 'master' into release/for_elite 2021-10-18 17:48:53 +08:00
Jordan Hsu 97993827b2 [update] api for checking if mini have data 2021-09-10 20:10:08 +08:00
55 changed files with 57586 additions and 1260 deletions
+6 -24
View File
@@ -23,26 +23,6 @@ createuser biopro -P --interactive
### Run apiServer on device
##### Install node.js
```
sudo apt-get upgrade
sudo apt-get update
```
```
### setup_14.x can change to your version
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
### install node and npm
sudo apt-get install -y nodejs
```
##### (optional) if the installation of node.js fail
```
sudo apt update
curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
sudo apt-get install -y nodejs
```
##### Clone project
```
git clone https://gitlab.com/bioproscientific/bioproapiserver.git
@@ -55,9 +35,12 @@ vim config.js
```
change the code following as:
```
/*
change apiserver port to postgres port, 54321 --> 5432 (default)
*/
export const pgDB = {
host: '127.0.0.1', // 服务器地址
port: 5432, // 数据库端口号
port: 54321, // 数据库端口号 -----------------> 5432
username: 'biopro', // 数据库用户名
password: 'BioProControlBox', // 数据库密码
database: 'postgres' // 数据库名称
@@ -77,8 +60,7 @@ sudo vim /etc/rc.local
```
add the code following as:
```
now=$(date +"%F_%T")
sudo -H -u pi nohup node /home/pi/bioproapiserver/dist/app.js > /home/pi/.api_server_$now.out &
nohup node /home/pi/bioproapiserver/dist/app.js > /home/pi/.api_server.out &
```
### Localhost develop
@@ -97,4 +79,4 @@ npm run start
```
##### References
>https://opensource.com/article/17/10/set-postgres-database-your-raspberry-pi
>https://opensource.com/article/17/10/set-postgres-database-your-raspberry-pi
-13
View File
@@ -2448,14 +2448,6 @@
"integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==",
"dev": true
},
"axios": {
"version": "0.24.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz",
"integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==",
"requires": {
"follow-redirects": "^1.14.4"
}
},
"babel-core": {
"version": "7.0.0-bridge.0",
"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz",
@@ -4868,11 +4860,6 @@
"readable-stream": "^2.3.6"
}
},
"follow-redirects": {
"version": "1.14.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA=="
},
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+1 -2
View File
@@ -7,14 +7,13 @@
"scripts": {
"start": "gulp nodemon",
"dev": "gulp",
"build": "babel src -d dist",
"build": "babel src -d dist --copy-files",
"production": "node dist/app.js",
"test": "jest",
"link": "eslint .",
"link:fix": "eslint --fix ."
},
"dependencies": {
"axios": "^0.24.0",
"jsonwebtoken": "^8.5.1",
"koa": "^2.11.0",
"koa-body": "^4.1.1",
+26 -26
View File
@@ -1,39 +1,39 @@
import path from 'path'
// system config
// 系统配置
export const System = {
API_server_type: 'http://',
API_server_host: 'localhost',
API_server_port: '3000',
HTTP_server_type: 'http://',
HTTP_server_host: 'www.XXX.com', // HTTP server addressas client browser location* if its app
HTTP_server_port: '65534',
System_country: 'zh-cn',
System_plugin_path: path.join(__dirname, './plugins'),
Session_Key: 'RESTfulAPI',
db_type: 'mysql'
API_server_type: 'http://', // API服务器协议类型,包含"http://"或"https://"
API_server_host: 'localhost', // API服务器暴露的域名地址,请勿添加"http://"
API_server_port: '3000', // API服务器监听的端口号
HTTP_server_type: 'http://', // HTTP服务器协议类型,包含"http://"或"https://"
HTTP_server_host: 'www.XXX.com', // HTTP服务器地址,请勿添加"http://" (即前端调用使用的服务器地址,如果是APP请设置为 *
HTTP_server_port: '65534', // HTTP服务器端口号
System_country: 'zh-cn', // 所在国家的国家代码
System_plugin_path: path.join(__dirname, './plugins'), // 插件路径
Session_Key: 'RESTfulAPI', // 生产环境务必随机设置一个值
db_type: 'mysql' // 数据库类型
}
export const DB = {
host: 'localhost',
port: 3306,
username: 'admin',
password: 'admin888',
database: 'development',
prefix: 'api_'
host: 'localhost', // 服务器地址
port: 3306, // 数据库端口号
username: 'admin', // 数据库用户名
password: 'admin888', // 数据库密码
database: 'development', // 数据库名称
prefix: 'api_' // 默认"api_"
}
export const pgDB = {
host: '127.0.0.1',
port: 5432,
username: 'biopro',
password: 'BioProControlBox',
database: 'postgres'
host: '127.0.0.1', // 服务器地址
port: 5432, // 数据库端口号
username: 'biopro', // 数据库用户名
password: 'BioProControlBox', // 数据库密码
database: 'postgres' // 数据库名称
}
export const SendEmail = {
service: 'smtp.abcd.com',
username: 'postmaster%40abcd.com',
password: 'password',
sender_address: '<postmaster@abcd.com>'
service: 'smtp.abcd.com', // SMTP服务提供商域名
username: 'postmaster%40abcd.com', // 用户名/用户邮箱
password: 'password', // 邮箱密码
sender_address: '"XX平台 👥" <postmaster@abcd.com>'
}
-38
View File
@@ -1,38 +0,0 @@
from scipy import signal
import sys
# argv = _type, order, fs, f0, f1, f2
if len(sys.argv) < 7:
_type = 'highpass' # 'highpass', 'lowpass', 'bandstop', 'bandpass'
order = 20
fs = 1000
f0 = 48
f1 = 52
f2 = 25
# exit()
else:
_type = sys.argv[1] # 'highpass', 'lowpass', 'bandstop', 'bandpass'
order = int(sys.argv[2])
fs = float(sys.argv[3])
f0 = float(sys.argv[4])
f1 = float(sys.argv[5])
f2 = float(sys.argv[6])
# fs = 1000
if _type in ['bandstop', 'bandpass']:
sos = signal.butter(order, [f0/fs*2,f1/fs*2], _type, output='sos')
elif _type in ['highpass', 'lowpass']:
sos = signal.butter(order, f2/fs*2, _type, output='sos')
else:
b, a = signal.iirnotch(f2, order, fs)
sos = signal.tf2sos(b, a)
ret = ''
for s_list in sos:
for s in s_list:
ret += str(s) + ','
ret = ret[:-1]
ret += '/'
print(ret[:-2], end='')
+32 -113
View File
@@ -1,138 +1,57 @@
import RecordingDataMeta from '../../models/file/recording_data_meta'
import RecordingDataRaw from '../../models/file/recording_data_raw'
import childProcess from 'child_process'
import path from 'path'
import { homedir } from 'os'
const recordingDataMeta = new RecordingDataMeta()
const recordingDataRaw = new RecordingDataRaw()
export const spikeDetect = async (ctx, next) => {
const request = ctx.request.body
ctx.req.setTimeout(0)
const controllerId = request.controller_id
const metaId = request.meta_id
const id = request.id
const channel = request.channel
const cutOffFreq = request.cut_off_freq
const filterOrder = request.filter_order
const threshold = request.threshold
const waveForm = request.waveForm
const dataType = request.data_type
const result = await recordingDataMeta.getByID(metaId)
const retDataType = request.ret_data_type
// console.log(id, channel, cutOffFreq, threshold, waveForm)
const result = await recordingDataMeta.getByID(id)
const channels = JSON.parse(result[0].channels)
const sampleRate = result[0].parameter_set.SAMPLE_RATE / channels.length
const sampleRate = 8e5 / result[0].parameter_set.ADC_CLOCK / channels.length
const timeDuration = result[0].time_duration / 1e6
let rawData = '[]'
if (dataType === 'filter_data') {
rawData = JSON.stringify(result[0].raw_data[channel])
} else if (dataType === 'filter_data_sd') {
const uuid = result[0].uuid
const ret = await recordingDataRaw.getSdDataAllTimeslotByUUID(uuid, channel)
console.log(uuid)
rawData = JSON.stringify(ret.map(r => r.id))
}
console.log(rawData)
// console.log(sampleRate, timeDuration)
function getPromise () {
return new Promise((resolve, reject) => {
const subprocess = childProcess.spawn('python3', [
path.join(homedir(), 'bioproanalysis', 'spike_detect', 'main.py'),
'controller_id=' + controllerId,
'meta_id=' + metaId,
'channel=' + channel,
'cut_off_freq=' + cutOffFreq,
'filter_order=' + filterOrder,
'threshold=' + threshold,
'waveform=' + waveForm,
'sample_rate=' + sampleRate,
'time_duration=' + timeDuration,
'data_type=' + dataType,
'raw_data=' + rawData,
])
const process = childProcess.spawnSync('python3', [
path.join(__dirname, '/spikeDetect.py'),
'meta_id=' + id,
'channel=' + channel,
'cut_off_freq=' + cutOffFreq,
'threshold=' + threshold,
'waveform=' + waveForm,
'sample_rate=' + sampleRate,
'time_duration=' + timeDuration,
'ret_data_type=' + retDataType
], { maxBuffer: 2 * 1024 * 1024 * 1024 })
let totalString = ''
// console.log('out', process.stdout.toString())
console.log('err', process.stderr.toString())
subprocess.stdout.on('data', async (data) => {
const dataString = data.toString()
totalString += dataString
})
ctx.body = process.stdout.toString()
subprocess.stderr.on('data', (error) => {
console.error(`Error ${error}`)
resolve(error)
return
})
// const process = child_process.execSync('python3 /Users/lubokai/Desktop/bioproapiserver/src/controllers/analysis/test.py 1089 0')
// console.log(process)
// process.stdout.on('data', (data) => {
// _data += data.toString()
// })
subprocess.on('close', (code) => {
console.log(totalString)
resolve(totalString)
console.log(`spike detect analysis process exited with code ${code}`)
})
})
}
// process.stderr.on('data', (data) => {
// console.error(data.toString())
// })
const ret = await getPromise()
ctx.body = ret
const msg = ret.toString()
const msgList = msg.split('\n')
if (msg.startsWith('Traceback')) {
if (msgList[msgList.length - 2].startsWith('ValueError')) {
ctx.status = 400
} else {
ctx.status = 500
}
}
next()
}
export const IIRFliter = async (ctx, next) => {
const request = ctx.request.body
ctx.req.setTimeout(0)
const type = request.type
const order = request.order
const fs = request.fs
const f0 = request.f0
const f1 = request.f1
const f2 = request.f2
function getPromise () {
return new Promise((resolve, reject) => {
const subprocess = childProcess.spawn('python3', [
path.join(homedir(), 'bioproanalysis', 'filter', 'IIRFilter.py'),
type,
order,
fs,
f0,
f1,
f2
])
let totalString = ''
subprocess.stdout.on('data', async (data) => {
const dataString = data.toString()
totalString += dataString
})
subprocess.stderr.on('data', (error) => {
reject(error)
console.error(`Error ${error}`)
})
subprocess.on('close', (code) => {
resolve(totalString)
console.log(`iir filter analysis process exited with code ${code}`)
})
})
}
const ret = await getPromise()
ctx.body = ret
// process.on('exit', (code) => {
// console.log(_data)
// console.log(`Child exited with code ${code}`)
// })
next()
}
+110
View File
@@ -0,0 +1,110 @@
import sys
import ast
import psycopg2
import numpy as np
import pandas as pd
from math import ceil, floor
from json import loads, dumps
from scipy.fft import fft, fftfreq, rfft, rfftfreq, irfft, ifft
if __name__ == '__main__':
params = {}
for input in sys.argv[1:]: #Now we're going to iterate over argv[1:] (argv[0] is the program name)
param = input.split("=") #Get what's left of the '='
params[param[0]] = param[1]
meta_id = params['meta_id']
channel = params['channel']
cut_off_freq = int(params['cut_off_freq'])
threshold = ast.literal_eval('[' + params['threshold'] + ']')
waveform = ast.literal_eval('[' + params['waveform'] + ']')
SAMPLE_RATE = int(params['sample_rate'])
DURATION = ceil(float(params['time_duration']))
DELTA_TIME = 1e6 / SAMPLE_RATE
N = SAMPLE_RATE * DURATION
ret_data_type = params['ret_data_type']
# print(meta_id, channel, cut_off_freq, threshold, waveForm, SAMPLE_RATE, DURATION, N)
conn = psycopg2.connect(database="postgres", user="biopro", password="BioProControlBox", host="127.0.0.1", port="5432")
cur = conn.cursor()
sql_str = 'SELECT data FROM "public"."' + str(channel) + '_recording_data_raws" WHERE parent = ' + meta_id + 'ORDER BY id ASC'
cur.execute(sql_str)
ret = None
try:
ret = cur.fetchall()
except BaseException as e:
print(e)
exit
finally:
time = np.array([], dtype=int)
data = np.array([])
for sub_data in ret:
for split_data in sub_data[0].split('"***"')[:-1]:
value = np.array(split_data.split(' '))
time = np.append(time, value[::2].astype(np.int))
data = np.append(data, value[1::2].astype(np.int))
# print(len(time), len(data))
xf = rfftfreq(N, 1 / SAMPLE_RATE)
points_per_freq = len(xf) / (SAMPLE_RATE / 2)
target_idx = int(points_per_freq * cut_off_freq)
# print(xf[target_idx])
yf = rfft(data)
yf[:target_idx] = 0
new_sig = np.round(irfft(yf, len(data)),3)
# print(time[-1])
# print(len(datas))
# print(len(yf),yf)
if threshold[0] == 'below':
th = new_sig < threshold[1]
elif threshold[0] == 'over':
th = new_sig > threshold[1]
elif threshold[0] == 'auto':
th = new_sig
threshold_edges = np.convolve([1, -1], th, mode='same')
thresholded_edge_indices = np.where(threshold_edges==1)[0]
filter_array = []
for idx, point in enumerate(thresholded_edge_indices):
if idx > 0:
if time[thresholded_edge_indices[idx]] - int(waveform[2]) >= time[thresholded_edge_indices[idx-1]]:
filter_array.append(True)
elif time[thresholded_edge_indices[idx]] - int(waveform[1]) >= time[thresholded_edge_indices[idx-1]]:
filter_array.append(True)
else:
filter_array.append(False)
else:
if time[thresholded_edge_indices[idx]] - int(waveform[1]) < 0:
filter_array.append(False)
else:
filter_array.append(True)
timemark_list = thresholded_edge_indices[filter_array]
if ret_data_type == 'all':
print(' '.join(str(x) for x in time))
print(' '.join(str(x) for x in new_sig))
print(' '.join(str(x) for x in timemark_list))
elif ret_data_type == 'partial':
return_sub_signal_lists = {}
for timemark in timemark_list:
start_index = timemark - floor(int(waveform[1] / DELTA_TIME))
end_index = timemark + ceil(int(waveform[2] / DELTA_TIME))
subSignal = new_sig[start_index: end_index + 2]
return_sub_signal_lists[str(timemark)] = ' '.join(str(x) for x in subSignal)
print(dumps(return_sub_signal_lists))
conn.commit()
conn.close()
exit
+11 -118
View File
@@ -1,19 +1,17 @@
import jwt from 'jsonwebtoken'
import fs from 'fs'
import path from 'path'
import childProcess from 'child_process'
import { readFile, writeFile } from 'fs/promises'
import { homedir } from 'os'
const axios = require('axios')
const crypto = require('crypto')
const publicKey = fs.readFileSync(path.join(__dirname, '../../publicKey.pub'))
const licenseUrl = 'http://52.194.17.114:3000'
const apiFuncName = 'apiServer'
// 用户登录的时候返回token
// let token = jwt.sign({
// userInfo: userInfo // 你要保存到token的数据
// }, publicKey, { expiresIn: '7d' })
export const getCookie = (ctx, next) => {
const token = jwt.sign({
userInfo: 'tommy'
userInfo: 'tommy' // 你要保存到token的数据
}, publicKey, { expiresIn: '7d' })
ctx.body = token
@@ -24,6 +22,9 @@ export const getCookie = (ctx, next) => {
// }
}
/**
* 检查授权是否合法
*/
export const CheckAuth = (ctx, next) => {
const token = ctx.request.header.authorization
try {
@@ -37,7 +38,7 @@ export const CheckAuth = (ctx, next) => {
return {
status: 403,
result: {
errInfo: 'no auth'
errInfo: '没有授权'
}
}
}
@@ -45,7 +46,7 @@ export const CheckAuth = (ctx, next) => {
return {
status: 503,
result: {
errInfo: 'decode fail'
errInfo: '解密错误'
}
}
}
@@ -59,111 +60,3 @@ export const Post = (ctx, next) => {
return CheckAuth(ctx).then(result => { ctx.body = result; next() })
}
}
export const updateLicense = async (ctx, next) => {
function wgetEXEC (url, name) {
return new Promise((resolve, reject) => {
const subprocess = childProcess.exec('wget ' + url + name + ' -O ' + homedir + '/checkToken')
subprocess.stdout.on('data', async (data) => {
})
// subprocess.stderr.on('data', (error) => {
// // reject(error)
// console.error(`Error ${error}`)
// })
subprocess.on('close', (code) => {
resolve(true)
console.log(`wgetEXE process exited with code ${code}`)
})
})
}
function chmodEXEC () {
return new Promise((resolve, reject) => {
const subprocess = childProcess.exec('chmod 777 ' + homedir + '/checkToken')
subprocess.stdout.on('data', async (data) => {
})
// subprocess.stderr.on('data', (error) => {
// // reject(error)
// console.error(`Error ${error}`)
// })
subprocess.on('close', (code) => {
resolve(true)
console.log(`wgetEXE process exited with code ${code}`)
return true
})
})
}
const mac = await readFile('/sys/class/net/eth0/address')
const ret = await axios.post(licenseUrl + '/api/controller/token', {
mac_controller: mac.toString().substr(0, 17)
})
switch (ret.status) {
case 200:
await writeFile(homedir + '/token.txt', ret.data.token)
await writeFile(homedir + '/cute.txt', ret.data.cute)
await wgetEXEC(licenseUrl + '/assets/exec/', ret.data.name)
await chmodEXEC()
ctx.status = 200
break
case 201:
await writeFile(homedir + '/token.txt', ret.data.token)
await writeFile(homedir + '/cute.txt', ret.data.cute)
await wgetEXEC(licenseUrl + '/assets/exec/', ret.data.name)
await chmodEXEC()
ctx.status = 200
break
case 202:
await writeFile(homedir + '/token.txt', ret.data.token)
await writeFile(homedir + '/cute.txt', ret.data.cute)
await wgetEXEC(licenseUrl + '/assets/exec/', ret.data.name)
await chmodEXEC()
ctx.status = 202
break
case 203:
ctx.status = 203
break
default:
ctx.status = 305
break
}
console.log(ret.status, ret.data)
// 200 success; 201 doesnt need to update; 202 no license; 203 info fail
ctx.body = ''
next()
}
export const checkLicense = async (ctx, next) => {
const mac = await readFile('/sys/class/net/eth0/address')
ctx.body = await runCheckToken(mac.toString().substr(0, 17))
next()
}
export const runCheckToken = async (mac) => {
return new Promise((resolve, reject) => {
const tokenPath = homedir + '/token.txt'
const cutePath = homedir + '/cute.txt'
const subprocess = childProcess.exec(homedir + '/./checkToken ' + apiFuncName + ' ' + tokenPath + ' ' + cutePath)
let _data = ''
subprocess.stdout.on('data', async (data) => {
_data += data
})
subprocess.on('close', (code) => {
const pass = crypto.createHmac('sha256', mac).update(apiFuncName + 'pass').digest('hex')
const outdated = crypto.createHmac('sha256', mac).update(apiFuncName + 'outdated').digest('hex')
switch (_data) {
case pass:
resolve('pass')
break
case outdated:
resolve('outdated')
break
default:
resolve('fail')
break
}
})
})
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+142
View File
@@ -0,0 +1,142 @@
import psycopg2
import pandas as pd
import numpy as np
from os.path import exists
import sys
import os
import time
def log(df, channel):
# TODO: not sure need use 32 or 64? => 64, since large integral will cause overflow
df[f'{channel}_log'] = np.log10(np.absolute(df[channel]))
# df[f'{channel}_log'] = np.log10(np.absolute(df[channel].astype(np.int64)))
return df
def integral(df, x_channel, y_channel, pre_last_x, pre_last_y, integral_result):
offset = df[x_channel]
offset = offset.shift(periods=1)
offset[0] = pre_last_x
x_diff = df[x_channel] - offset
# x_diff = df[x_channel].astype(np.int64) - offset.astype(np.int64)
# print('x_diff\n', x_diff)
offset = df[y_channel]
offset = offset.shift(periods=1)
offset[0] = pre_last_y
y_avg = (offset + df[y_channel]) / 2
# y_avg = (offset.astype(np.int64) + df[y_channel].astype(np.int64)) / 2
# print('y_avg:', y_avg)
# print('y_avg: ', y_avg)
local_integral = x_diff * y_avg
# TODO: if user don't need, then can remove it
df[f'{x_channel}_{y_channel}_integral_delta'] = local_integral
local_integral[0] += integral_result
df[f'{x_channel}_{y_channel}_integral'] = local_integral.cumsum()
# print(df)
pre_last_x = df[x_channel].iat[-1]
pre_last_y = df[y_channel].iat[-1]
integral_result = df[f'{x_channel}_{y_channel}_integral'].iat[-1]
# print('next run info: ', pre_last_x, pre_last_y, integral_result)
return df, pre_last_x, pre_last_y, integral_result
def differential(df, x_channel, y_channel, pre_last_x, pre_last_y):
offset = df[x_channel]
offset = offset.shift(periods=1)
offset[0] = pre_last_x
x_diff = df[x_channel] - offset
# x_diff = df[x_channel].astype(np.int64) - offset.astype(np.int64)
offset = df[y_channel]
offset = offset.shift(periods=1)
offset[0] = pre_last_y
y_diff = df[y_channel] - offset
# y_diff = df[y_channel].astype(np.int64) - offset.astype(np.int64)
local_diff = y_diff / x_diff
# TODO: if user don't need, then can remove it
df[f'{x_channel}_{y_channel}_diff'] = local_diff
pre_last_x = df[x_channel].iat[-1]
pre_last_y = df[y_channel].iat[-1]
return df, pre_last_x, pre_last_y
def download(id, mode, x_channel, y_channel):
# TODO: can change different chunck size
pages_chunck_size = 250
sql_total = 0
conn_start = time.time()
# TODO: need the check port id
conn = psycopg2.connect(database="postgres", user="biopro", password="BioProControlBox", host="127.0.0.1", port="54321")
print('conn time: ', time.time() - conn_start)
# conn = psycopg2.connect(database="postgres", user="biopro", password="BioProControlBox", host="127.0.0.1", port="5432")
cur = conn.cursor()
# recording_data_metas: meta info to get the raw_data table
sql_str = f'select "raw_data" from "recording_data_metas" WHERE id = {id}'
first_sql = time.time()
cur.execute(sql_str)
print('first sql time: ', time.time() - first_sql)
raw_data_list = None
try:
raw_data_list = cur.fetchall()[0][0]
channels = list(raw_data_list.keys())
df_all = pd.DataFrame()
# df = pd.DataFrame()
df_time = []
pre_last_x = 0
pre_last_y = 0
integral_result = 0
for raw_data_pages in range(len(raw_data_list[channels[0]])):
df = pd.DataFrame()
for channel in channels:
sql_str = f'select "data" from "{channel}_recording_data_raws" WHERE id = {raw_data_list[channel][raw_data_pages]}'
sql_start = time.time()
cur.execute(sql_str)
sql_total += (time.time() - sql_start)
data_value = cur.fetchall()[0][0].replace('"***"', ' ')
data_value = data_value.split(' ')[:-1]
if df.empty:
df_time = data_value[::2]
df[channel] = data_value
df = df.iloc[lambda x: x.index % 2 == 1].reset_index(drop=True)
df.insert(0, 'Time', df_time)
# transfer dataframe from string to number
cols = df.columns
df[cols] = df[cols].apply(pd.to_numeric, errors='coerce')
if mode == 'Log':
df = log(df, x_channel)
elif mode == 'Integral':
df, pre_last_x, pre_last_y, integral_result = integral(df, x_channel, y_channel, pre_last_x, pre_last_y, integral_result)
elif mode == 'Differential':
df, pre_last_x, pre_last_y = differential(df, x_channel, y_channel, pre_last_x, pre_last_y)
df_all = pd.concat([df_all, df], ignore_index=True, sort=False)
if ~raw_data_pages and (raw_data_pages % pages_chunck_size == 0 or raw_data_pages == len(raw_data_list[channels[0]]) - 1):
if not(exists(f"./src/csv/{id}.csv")):
df.to_csv(f"./src/csv/{id}.csv", mode='a', index=False, header=True)
else:
df.to_csv(f"./src/csv/{id}.csv", mode='a', index=False, header=False)
""" if not(exists(f"./{id}.csv")):
df_all.to_csv(f"./{id}.csv", mode='a', index=False, header=True)
else:
df_all.to_csv(f"./{id}.csv", mode='a', index=False, header=False) """
df_all = pd.DataFrame()
print('total sql: ', sql_total)
except BaseException as e:
print(e)
exit
return
if __name__ == '__main__':
params = {}
for input in sys.argv[1:]: #Now we're going to iterate over argv[1:] (argv[0] is the program name)
param = input.split("=") #Get what's left of the '='
params[param[0]] = param[1]
id = params['id']
mode = params['mode']
x_channel = params['x_channel']
y_channel = params['y_channel']
# print('download_functional init at main: ', id, mode, x_channel, y_channel)
start_time = time.time()
download(id, mode, x_channel, y_channel)
# download(408, '', 'Time', '0')
# download(408, '', 'Time', '0')
# download(405, 'Integral', 'Time', '0')
# download(405, 'Integral', 'Time', '0')
# download(408, 'Integral', 'Time', '0')
print('total: ', time.time() - start_time)
# download(1262, 'differential', '1', '0')
# 1262/differential/1/0
+10 -18
View File
@@ -1,9 +1,7 @@
import RecordingDataMeta from '../../models/file/recording_data_meta'
import * as auth from '../../controllers/auth'
import RecordingMeta from '../../models/file/bps_recording_meta'
const recordingDataMeta = new RecordingDataMeta()
const recordingMeta = new RecordingMeta() // control system 3.0
export const create = async (ctx, next) => {
const data = ctx.request.body
@@ -50,6 +48,16 @@ export const getByParent = async (ctx, next) => {
next()
}
export const getAttrByParent = async (ctx, next) => {
const type = ctx.params.type
const parent = ctx.params.parent
const attr = ctx.params.attr
const result = await recordingDataMeta.getByAttrParent(type, parent, attr)
ctx.body = result
next()
}
export const getCountByParent = async (ctx, next) => {
const type = ctx.params.type
const parent = ctx.params.parent
@@ -122,19 +130,3 @@ export const getAll = async (ctx, next) => {
next()
}
// control system 3.0
export const getMetaByUUID = async (ctx, next) => {
const uuid = ctx.params.uuid
const result = await recordingMeta.getMetaByUUID(uuid)
ctx.body = result
next()
}
export const getMetaAll = async (ctx, next) => {
const result = await recordingMeta.getMetaAll()
ctx.body = result
next()
}
@@ -61,6 +61,15 @@ export const getByID = async (ctx, next) => {
next()
}
export const getExistOrNotByID = async (ctx, next) => {
const index = ctx.params.channel
const id = ctx.params.id
const result = await recordingDataMini.getExistOrNotByID(id, index)
ctx.body = result
next()
}
export const getByIDs = async (ctx, next) => {
const index = ctx.params.channel
const id = ctx.params.id
+39 -20
View File
@@ -1,7 +1,12 @@
import RecordingDataRaw from '../../models/file/recording_data_raw'
import RecordingDataMeta from '../../models/file/recording_data_meta'
import * as auth from '../auth'
import childProcess from 'child_process'
import path from 'path'
import { createReadStream } from 'fs'
const recordingDataRaw = new RecordingDataRaw()
const recordingDataMeta = new RecordingDataMeta()
export const create = async (ctx, next) => {
const index = ctx.params.channel
@@ -80,26 +85,6 @@ export const getDataByID = async (ctx, next) => {
next()
}
export const getSdDataByUUID = async (ctx, next) => {
const uuid = ctx.params.uuid
const channel = ctx.params.channel
const startTime = ctx.params.startTime
const endTime = ctx.params.endTime
const result = await recordingDataRaw.getSdDataByUUID(uuid, channel, startTime, endTime)
ctx.body = result
next()
}
export const getSdDataAllTimeslotByUUID = async (ctx, next) => {
const uuid = ctx.params.uuid
const channel = ctx.params.channel
const result = await recordingDataRaw.getSdDataAllTimeslotByUUID(uuid, channel)
ctx.body = result
next()
}
export const getByParent = async (ctx, next) => {
const index = ctx.params.channel
const parent = ctx.params.parent
@@ -182,3 +167,37 @@ export const getAll = async (ctx, next) => {
next()
}
export const getCSV = async (ctx, next) => {
const id = ctx.params.id
const mode = ctx.params.mode
const x_channel = ctx.params.x_channel
const y_channel = ctx.params.y_channel
// console.log('getCSV: ', id, mode, x_channel, y_channel)
// const result = await recordingDataRaw.getCSV(id, mode, x_channel, y_channel)
const process = childProcess.spawnSync('python', [
path.join(__dirname, '/download_functional.py'),
'id=' + id,
'mode=' + mode,
'x_channel=' + x_channel,
'y_channel=' + y_channel,
], { maxBuffer: 2 * 1024 * 1024 * 1024 })
// console.log('process: ', process)
// process.stdout.on('data', (data) => {
// conosle.log('data', data)
// })
const result = await recordingDataMeta.getByID(id)
// console.log('result: ', result)
// console.log('result: ', result[0]['dataValues']['name'])
var file_name = id + '.csv'
// ctx.body = fs.stdout.toString()
// console.log('process.stdout.toString(): ', process.stdout.toString())
// console.log('process.stderr.toString(): ', process.stderr.toString())
ctx.type = 'stream'
ctx.attachment(result[0]['dataValues']['name']+'.csv')
ctx.body = createReadStream(path.resolve(__dirname, '../../csv', file_name))
// need to remove the csv file after download, since using 'append' for set header one time
const fs = require('fs')
fs.unlinkSync(path.resolve(__dirname, '../../csv', file_name))
next()
}
-200
View File
@@ -1,200 +0,0 @@
import RecordingDataMeta from '../../../models/file/recording_data_meta'
import RecordingDataRaw from '../../../models/file/recording_data_raw'
import Controller from '../../../models/product/controller'
import childProcess from 'child_process'
import path from 'path'
import { homedir } from 'os'
const recordingDataMeta = new RecordingDataMeta()
const recordingDataRaw = new RecordingDataRaw()
const controller = new Controller()
const sdPath = [homedir(), 'bioproanalysis', 'sdcard']
const sdGetPath = [...sdPath, 'neuLiveSD_C', 'sd_list']
const sdDeletePath = [...sdPath, 'neuLiveSD_C', 'sd_remove']
const sdUploadPath = [...sdPath, 'sd_download.py']
const getParameter = async (metaID, parameterName) => {
const ret = await recordingDataMeta.getByID(metaID)
return ret[0].parameter_set[parameterName]
}
const getPath = async (uuid) => {
return getPathByUuid(uuid, getUuidPathArray(await getUuidPathStringPromise()))
}
const getPathByUuid = (uuid, uuidPathArray) => {
for (const uuidPath of uuidPathArray) {
if (uuidPath[0] === uuid) {
return uuidPath[1]
}
}
}
// [uuid1, uuid2, uuid3...]
const getUuidList = (uuidPathString) => {
return uuidPathString.split('\n').map(val => val.split(' ')[0])
}
// [[uuid1, path1], [uuid2, path2], [uuid3, path3]...]
const getUuidPathArray = (uuidPathString) => {
return uuidPathString.split('\n').map(val => val.split(' '))
}
// 'uuid1 path1\n uuid2 path2\n uuid3 path3\n....'
const getUuidPathStringPromise = async () => {
return new Promise((resolve, reject) => {
const subprocess = childProcess.spawn(path.join(...sdGetPath))
let dataString = ''
subprocess.stdout.on('data', async (data) => {
dataString += data.toString()
})
subprocess.stderr.on('data', (error) => {
console.error(`Error ${error}`)
reject(error)
})
subprocess.on('close', (code) => {
console.log(`sdcard get process exited with code ${code}`)
resolve(dataString)
})
})
}
function uploadPromise (uuid) {
return new Promise((resolve, reject) => {
const subprocess = childProcess.spawn('python3', [
path.join(...sdUploadPath),
uuid,
])
let dataString = ''
subprocess.stdout.on('data', async (data) => {
dataString += data.toString()
console.log('upload', dataString)
})
subprocess.stderr.on('data', (error) => {
reject(error)
console.error(`Error ${error}`)
})
subprocess.on('close', (code) => {
console.log(`sd card upload process exited with code ${code}`)
resolve(dataString)
})
})
}
function deletePromise (uuidPath) {
return new Promise((resolve, reject) => {
const subprocess = childProcess.spawn(
path.join(...sdDeletePath),
[uuidPath, 120]
)
let dataString = ''
subprocess.stdout.on('data', async (data) => {
dataString += data.toString()
})
subprocess.stderr.on('data', (error) => {
console.error(`Error ${error}`)
reject(error)
})
subprocess.on('close', (code) => {
console.log(`grep process exited with code ${code}`)
resolve(dataString)
})
})
}
export const exist = async (ctx, next) => {
const request = ctx.request.body
// const controllerID = request.controllerID
const uuid = request.uuid
const path = await getPath(uuid)
let result
(path !== undefined) ? result = true : result = false
ctx.body = result
next()
}
export const uploadThenDelete = async (ctx, next) => {
const request = ctx.request.body
const controllerID = request.controllerID
const metaID = request.metaID
const uuid = request.uuid
// timeout defualt 120s to no-limit
ctx.req.setTimeout(0)
// controller column sd_uploading update
await controller.update({
sd_uploading: true
}, controllerID)
let uploadResult = await uploadPromise(uuid)
if (uploadResult === 'true') {
// [Region] then doubly check if sd raw data table actually has data
const meta = await recordingDataMeta.getByUUID(uuid)
const channel = JSON.parse(meta[0].channels)[0]
const sdDataRes = await recordingDataRaw.getSdDataAllTimeslotByUUID(uuid, channel)
if (sdDataRes.length > 0) {
// [EndRegion]
await recordingDataMeta.update({
sd_data_uploaded: true
}, metaID)
// await deletePromise(uuidPath)
} else {
uploadResult = 'false'
}
}
// controller column sd_uploading close
await controller.update({
sd_uploading: false
}, controllerID)
ctx.body = uploadResult
next()
}
export const getFileList = async (ctx, next) => {
const result = await getUuidPathStringPromise()
const uuidList = getUuidList(result)
ctx.body = uuidList
next()
}
// export const deleted = async (ctx, next) => {
// const request = ctx.request.body
// const controllerID = request.controllerID
// const uuid = request.uuid
// const uuidPath = await getPath(uuid)
// // timeout defualt 120s to no-limit
// ctx.req.setTimeout(0)
// // controller column sd_uploading update
// await controller.update({
// sd_uploading: true
// }, controllerID)
// const result = await deletePromise(uuidPath)
// // controller column sd_uploading close
// await controller.update({
// sd_uploading: false
// }, controllerID)
// ctx.body = result
// next()
// }
-25
View File
@@ -1,25 +0,0 @@
import SDRawNeulive from '../../models/file/sd_raw_neulive'
import * as auth from '../auth'
const sdRawNeulive = new SDRawNeulive()
export const create = async (ctx, next) => {
const data = ctx.request.body
const result = await sdRawNeulive.create(data)
ctx.body = result
next()
}
export const getByParentUUID = async (ctx, next) => {
const parent_uuid = ctx.params.parent_uuid
const result = await sdRawNeulive.getByParentUUID(parent_uuid)
ctx.body = result
next()
}
export const clearDeleted = async (ctx, next) => {
const parent_uuid = ctx.params.parent_uuid
const result = await sdRawNeulive.clearDeleted(parent_uuid)
ctx.body = result
next()
}
+60
View File
@@ -0,0 +1,60 @@
time 0 1 2 3 time_0_integral
0 0 -73922 -836265 -848970 0 0.000000e+00
1 10500 -84368 -834380 -848548 0 -8.310225e+08
2 21000 -84389 -834380 -848126 0 -1.716997e+09
3 31500 -84332 -835637 -847704 0 -2.602782e+09
4 42500 -84166 -835637 -847283 0 -3.529521e+09
... ... ... ... ... .. ...
1462 15390500 -45761 -449806 -466674 0 -9.716838e+11
1463 15401000 -45833 -449806 -466445 0 -9.721646e+11
1464 15411500 -45790 -451063 -466216 0 -9.726457e+11
1465 15422500 -45638 -449806 -465988 0 -9.731485e+11
1466 15432500 -45674 -449806 -465759 0 -9.736051e+11
[1467 rows x 6 columns]
next run info: 15432500 -45674 -973605066500.0
time 0 1 2 3 time_0_integral
0 15443000 -45689 -448549 -465531 0 -9.740847e+11
1 15453500 -45689 -448549 -465531 0 -9.745645e+11
2 15464000 -45631 -449178 -465303 0 -9.750439e+11
3 15474500 -45581 -447921 -465075 0 -9.755227e+11
4 15485500 -45646 -447921 -464847 0 -9.760245e+11
... ... ... ... ... .. ...
1443 30720000 -24971 -248122 -259749 0 -1.497382e+12
1444 30730500 -24920 -247950 -259624 0 -1.497644e+12
1445 30741000 -24920 -248381 -259624 0 -1.497905e+12
1446 30751500 -24791 -248036 -259500 0 -1.498166e+12
1447 30762000 -24856 -247346 -259376 0 -1.498427e+12
[1448 rows x 6 columns]
next run info: 30762000 -24856 -1498426872750.0
time 0 1 2 3 time_0_integral
0 30772500 -24913 -247669 -259251 0 -1.498688e+12
1 30783000 -24848 -247669 -259127 0 -1.498949e+12
2 30794000 -24805 -247669 -259003 0 -1.499222e+12
3 30804000 -24805 -247454 -259003 0 -1.499471e+12
4 30814500 -24870 -247238 -258879 0 -1.499731e+12
... ... ... ... ... .. ...
1456 46091500 -13496 -134943 -147002 0 -1.783935e+12
1457 46102000 -13510 -134921 -146934 0 -1.784077e+12
1458 46112500 -13510 -134123 -146934 0 -1.784219e+12
1459 46123000 -13597 -134339 -146866 0 -1.784361e+12
1460 46134000 -13525 -134598 -146799 0 -1.784510e+12
[1461 rows x 6 columns]
next run info: 46134000 -13525 -1784510350500.0
time 0 1 2 3 time_0_integral
0 46144500 -13366 -134210 -146732 0 -1.784652e+12
1 46154500 -13460 -134210 -146665 0 -1.784786e+12
2 46165500 -13503 -134016 -146597 0 -1.784934e+12
3 46176000 -13503 -134102 -146597 0 -1.785076e+12
4 46186500 -13431 -134167 -146530 0 -1.785217e+12
.. ... ... ... ... .. ...
583 52277500 -10487 -105193 -117883 0 -1.858083e+12
584 52288000 -10573 -105042 -117830 0 -1.858194e+12
585 52298500 -10595 -105106 -117778 0 -1.858305e+12
586 52309000 -10494 -105085 -117725 0 -1.858415e+12
587 52319500 -10523 -105085 -117672 0 -1.858526e+12
[588 rows x 6 columns]
next run info: 52319500 -10523 -1858525771000.0
-11
View File
@@ -1,11 +0,0 @@
import RawTrigger from '../../../models/file/bps_raw_trigger'
const rawTrigger = new RawTrigger()
export const getRawTriggerByUUID = async (ctx, next) => {
const parent_uuid = ctx.params.parent_uuid
const result = await rawTrigger.getDataByUUID(parent_uuid)
ctx.body = result
next()
}
+2 -4
View File
@@ -9,8 +9,7 @@ import * as recordingDataMeta from './file/recording_data_meta'
import * as recordingDataRaw from './file/recording_data_raw'
import * as recordingDataMini from './file/recording_data_mini'
import * as analysis from './analysis'
import * as sdCard from './file/sd_card'
import * as trigger from './file/trigger'
import * as project from './project/project'
export default {
upload,
@@ -24,6 +23,5 @@ export default {
recordingDataRaw,
recordingDataMini,
analysis,
sdCard,
trigger,
project
}
+9 -16
View File
@@ -19,6 +19,15 @@ export const update = async (ctx, next) => {
next()
}
export const updateByID = async (ctx, next) => {
const data = ctx.request.body
const id = ctx.params.id
const result = await controller.updateByID(data, id)
ctx.body = result
next()
}
export const updateByAttr = async (ctx, next) => {
const data = ctx.request.body
const attr = ctx.params.attr
@@ -36,14 +45,6 @@ export const clearDeleted = async (ctx, next) => {
next()
}
export const getByName = async (ctx, next) => {
const name = ctx.params.name
const result = await controller.getByName(name)
ctx.body = result
next()
}
export const getByMac = async (ctx, next) => {
const mac = ctx.params.mac
const result = await controller.getByMac(mac)
@@ -52,14 +53,6 @@ export const getByMac = async (ctx, next) => {
next()
}
export const getByMqttId = async (ctx, next) => {
const mqttId = ctx.params.mqtt_id
const result = await controller.getByMqttId(mqttId)
ctx.body = result
next()
}
export const getByAttr = async (ctx, next) => {
const attr = ctx.params.attr
const value = ctx.params.value
+9 -1
View File
@@ -11,9 +11,17 @@ export const create = async (ctx, next) => {
}
export const update = async (ctx, next) => {
const data = ctx.request.body
const result = await device.update(data)
ctx.body = result
next()
}
export const updateByID = async (ctx, next) => {
const data = ctx.request.body
const id = ctx.params.id
const result = await device.update(data, id)
const result = await device.updateByID(data, id)
ctx.body = result
next()
+62
View File
@@ -0,0 +1,62 @@
import ProjectModal from '../../models/project/project'
const project = new ProjectModal()
export const create = async (ctx, next) => {
const data = ctx.request.body
console.log('create', data)
const result = await project.create(data)
ctx.body = result
next()
}
export const update = async (ctx, next) => {
const data = ctx.request.body
const id = ctx.params.id
const result = await project.update(data, id)
ctx.body = result
next()
}
export const updateByAttr = async (ctx, next) => {
const attr = ctx.params.attr
const value = ctx.params.value
const result = await project.updateByAttr(attr, value)
ctx.body = result
next()
}
export const clearDeleted = async (ctx, next) => {
const result = await project.clearDeleted()
ctx.body = result
next()
}
export const getByID = async (ctx, next) => {
const index = ctx.params.channel
const id = ctx.params.id
const result = await project.getByID(id, index)
ctx.body = result
next()
}
export const getByAttr = async (ctx, next) => {
const attr = ctx.params.attr
const value = ctx.params.value
const result = await project.getByAttr(attr, value)
ctx.body = result
next()
}
export const getAll = async (ctx, next) => {
const result = await project.getAll()
ctx.body = result
next()
}
+9 -12
View File
@@ -27,23 +27,20 @@ db.controllers = require('./schema/controller.model')(sequelize, Sequelize)
db.tasks = require('./schema/task.model')(sequelize, Sequelize)
db.devices = require('./schema/device.model')(sequelize, Sequelize)
db.collections = require('./schema/collection.model')(sequelize, Sequelize)
db.projects = require('./schema/project.model')(sequelize, Sequelize)
db.recording_data_metas = require('./schema/recording_data_meta.model')(sequelize, Sequelize)
for (let i = 0; i < 64; i++) {
for (let i = 0; i < 32; i++) {
db[i + '_recording_data_raws'] = require('./schema/recording_data_raw.model')(sequelize, Sequelize, i)
}
for (let i = 0; i < 64; i++) {
for (let i = 0; i < 32; i++) {
db[i + '_recording_data_minis'] = require('./schema/recording_data_mini.model')(sequelize, Sequelize, i)
}
for (let i = 256; i < 288; i++) {
db[i + '_recording_data_raws'] = require('./schema/recording_data_raw.model')(sequelize, Sequelize, i)
}
for (let i = 256; i < 288; i++) {
db[i + '_recording_data_minis'] = require('./schema/recording_data_mini.model')(sequelize, Sequelize, i)
}
db.recording_meta = require('./schema/bps_recording_meta.model')(sequelize, Sequelize)
db.raw_trigger = require('./schema/bps_raw_trigger.model')(sequelize, Sequelize)
db.sd_raw_neulive = require('./schema/sd_raw_neulive.model')(sequelize, Sequelize)
// for (let i = 256; i < 288; i++) {
// db[i + '_recording_data_raws'] = require('./schema/recording_data_raw.model')(sequelize, Sequelize, i)
// }
// for (let i = 256; i < 288; i++) {
// db[i + '_recording_data_minis'] = require('./schema/recording_data_mini.model')(sequelize, Sequelize, i)
// }
db.sequelize.sync()
-34
View File
@@ -1,34 +0,0 @@
module.exports = (sequelize, Sequelize) => {
const TriggerDataRaw = sequelize.define('bps_raw_trigger', {
channel: {
type: Sequelize.INTEGER,
defaultValue: -1
},
parent_uuid: {
type: Sequelize.STRING,
defaultValue: ''
},
data: {
type: Sequelize.TEXT,
defaultValue: ''
},
timestamp: {
type: Sequelize.TEXT,
defaultValue: ''
},
start_time: {
type: Sequelize.STRING,
defaultValue: '-1'
},
end_time: {
type: Sequelize.STRING,
defaultValue: '-1'
},
},
{
freezeTableName: true
}
)
return TriggerDataRaw
}
-78
View File
@@ -1,78 +0,0 @@
module.exports = (sequelize, Sequelize) => {
const RecordingMeta = sequelize.define('bps_recording_meta', {
uuid: {
type: Sequelize.STRING,
defaultValue: '',
primaryKey: true
},
name: {
type: Sequelize.STRING
},
series: {
type: Sequelize.STRING
},
folder_id: {
type: Sequelize.INTEGER,
defaultValue: -1
},
task_uuid: {
type: Sequelize.STRING,
defaultValue: ''
},
device: {
type: Sequelize.JSONB,
defaultValue: {}
},
description: {
type: Sequelize.STRING,
defaultValue: ''
},
size: {
type: Sequelize.INTEGER,
defaultValue: -1
},
sd_size: {
type: Sequelize.INTEGER,
defaultValue: -1
},
time_duration_sec: {
type: Sequelize.INTEGER,
defaultValue: 0
},
time_duration_micro: {
type: Sequelize.INTEGER,
defaultValue: 0
},
sample_rate: {
type: Sequelize.INTEGER,
defaultValue: -1
},
deleted: {
type: Sequelize.BOOLEAN,
defaultValue: false
},
tag: {
type: Sequelize.STRING,
defaultValue: '-1'
},
parameter_set: {
type: Sequelize.ARRAY(Sequelize.JSONB),
defaultValue: []
},
create_date: {
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
},
channel: {
type: Sequelize.ARRAY(Sequelize.INTEGER),
defaultValue: []
}
},
{
timestamps: false
}
)
return RecordingMeta
}
-4
View File
@@ -104,10 +104,6 @@ module.exports = (sequelize, Sequelize) => {
type: Sequelize.STRING,
defaultValue: ''
},
sd_uploading: {
type: Sequelize.BOOLEAN,
defaultValue: false
},
deleted: {
type: Sequelize.BOOLEAN,
defaultValue: false
+47
View File
@@ -0,0 +1,47 @@
module.exports = (sequelize, Sequelize) => {
const Project = sequelize.define('project', {
name: {
type: Sequelize.STRING
},
desc: {
type: Sequelize.STRING
},
task: {
type: Sequelize.JSONB,
defaultValue: {}
},
device: {
type: Sequelize.JSONB,
defaultValue: {}
},
uuid: {
type: Sequelize.STRING,
defaultValue: ''
},
user_auth: {
type: Sequelize.JSONB,
defaultValue: {
owner: [],
maintainer: [],
guest: []
}
},
deleted: {
type: Sequelize.BOOLEAN,
defaultValue: false
},
created_at: {
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
},
updated_at: {
type: Sequelize.DATE,
defaultValue: Sequelize.literal('CURRENT_TIMESTAMP')
}
},
{
timestamps: false
})
return Project
}
@@ -25,10 +25,6 @@ module.exports = (sequelize, Sequelize) => {
type: Sequelize.STRING,
defaultValue: '-1'
},
start_time_abs: {
type: Sequelize.STRING,
defaultValue: '0'
},
time_duration: {
type: Sequelize.STRING,
defaultValue: '0'
@@ -77,14 +73,6 @@ module.exports = (sequelize, Sequelize) => {
type: Sequelize.TEXT,
defaultValue: ''
},
sd_data_record: {
type: Sequelize.BOOLEAN,
defaultValue: true
},
sd_data_uploaded: {
type: Sequelize.BOOLEAN,
defaultValue: false
},
deleted: {
type: Sequelize.BOOLEAN,
defaultValue: false
@@ -43,10 +43,6 @@ module.exports = (sequelize, Sequelize, i) => {
type: Sequelize.TEXT,
defaultValue: ''
},
sd_data: {
type: Sequelize.TEXT,
defaultValue: ''
},
compressed: {
type: Sequelize.BOOLEAN,
defaultValue: false
-41
View File
@@ -1,41 +0,0 @@
module.exports = (sequelize, Sequelize, i) => {
const RecordingDataRaw = sequelize.define('bps_sd_raw_neulive', {
channel: {
type: Sequelize.INTEGER
},
parent_uuid: {
type: Sequelize.STRING,
},
data: {
type: Sequelize.TEXT,
defaultValue: ''
},
data_time: {
type: Sequelize.TEXT,
defaultValue: ''
},
start_time_sec: {
type: Sequelize.INTEGER,
defaultValue: 0
},
end_time_sec: {
type: Sequelize.INTEGER,
defaultValue: 0
},
start_time_micro: {
type: Sequelize.INTEGER,
defaultValue: 0
},
end_time_micro: {
type: Sequelize.INTEGER,
defaultValue: 0
}
},
{
freezeTableName: true,
timestamps: false
}
)
return RecordingDataRaw
}
-42
View File
@@ -1,42 +0,0 @@
const db = require('../../db/database')
const { Transform } = require("stream")
class RawTrigger {
async getDataByUUID (parent_uuid) {
const ret = await db.raw_trigger.findAllWithStream(
{
where: {
parent_uuid: parent_uuid
},
attributes: [
'data'
],
}
)
const transformer = new Transform({
transform(chunk, encoding, callback) {
const chunkDataStr = chunk.toString('utf8')
// replace: ref https://dmitripavlutin.com/replace-all-string-occurrences-javascript/#2-replace-with-a-global-regular-expression
// slice: remove last ','
const transformDataArr = JSON.parse(chunkDataStr)[0].data.replace(/[@#$]/g, '').slice(0, -1).split(',')
const step = 3
let transformData = ''
for (let startPos = 0; startPos < transformDataArr.length; startPos += step) {
// array chunking algo. comparison: https://www.better.dev/javascript-algorithms-array-chunking
let temp = transformDataArr.slice(startPos, startPos + step)
const date = new Date(parseInt(temp[0]))
temp[0] = date
temp[1] = parseInt(temp[1]) + 1
temp.splice(1, 0, [date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds()].join(':'))
transformData += (temp.join() + '\n') // join: https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Global_Objects/Array/join
}
callback(null, transformData)
},
})
return ret.pipe(transformer)
}
}
export default RawTrigger
-37
View File
@@ -1,37 +0,0 @@
const db = require('../../db/database')
class RecordingMeta {
async getMetaByUUID (uuid) {
const ret = await db.recording_meta.findAll(
{
where: {
uuid: uuid
}
}
)
return ret
}
async getMetaAll () {
const ret = await db.recording_meta.findAll({
order: [
['create_date', 'DESC']
]
})
return ret
}
async clearDeleted (uuid) {
const ret = await db.recording_meta.destroy(
{
where: {
uuid: uuid
}
}
)
return ret
}
}
export default RecordingMeta
+24 -12
View File
@@ -1,15 +1,10 @@
import RecordingDataRaw from './recording_data_raw'
import RecordingDataMini from './recording_data_mini'
import SDRawNeulive from './sd_raw_neulive'
import RecordingMeta from '../../models/file/bps_recording_meta'
const db = require('../../db/database')
// const RecordingDataMini = require('./recording_data_mini')
const recordingDataRaw = new RecordingDataRaw()
const recordingDataMini = new RecordingDataMini()
const sdRawNeulive = new SDRawNeulive()
const recordingMeta = new RecordingMeta() // control system 3.0
const Op = db.Sequelize.Op
@@ -52,8 +47,7 @@ class RecordingDataMeta {
attributes: [
'id',
'raw_data',
'mini_data',
'uuid'
'mini_data'
],
where: {
deleted: true
@@ -74,8 +68,6 @@ class RecordingDataMeta {
recordingDataMini.clearDeleted(channel)
}
}
recordingMeta.clearDeleted(meta.uuid) // control system 3.0
sdRawNeulive.clearDeleted(meta.uuid)
}
ret = await db.recording_data_metas.destroy(
{
@@ -106,7 +98,28 @@ class RecordingDataMeta {
return ret
}
async getCountByParent (type, parent) {
async getByAttrParent(type, parent, attr) {
const attrList = attr.split('-')
const collectionType = type + '::jsonb'
const parentOp = {}
parentOp[collectionType] = {
[Op.contains]: '[' + parent + ']'
}
const ret = await db.recording_data_metas.findAll(
{
where: {
parent: parentOp
},
attributes: attrList,
order: [
['id', 'DESC']
],
}
)
return ret
}
async getCountByParent(type, parent) {
const collectionType = type + '::jsonb'
const parentOp = {}
parentOp[collectionType] = {
@@ -183,8 +196,7 @@ class RecordingDataMeta {
{
where: {
uuid: uuid
},
raw: true
}
}
)
return ret
+13 -2
View File
@@ -31,11 +31,11 @@ class RecordingDataMini {
return ret
}
async clearDeleted (index) {
async clearDeleted (index, where = { deleted: true }) {
const ret = await db[index + '_recording_data_minis'].destroy(
{
where: {
deleted: true
...where
}
}
)
@@ -69,6 +69,17 @@ class RecordingDataMini {
return ret
}
async getExistOrNotByID (id, index) {
const ret = await db[index + '_recording_data_minis'].findOne(
{
where: {
id: id
}
}
).then(token => !(token.data_mean === ''))
return ret
}
async getByIDs (id, index) {
const _id = JSON.parse('[' + id + ']')
const ret = await db[index + '_recording_data_minis'].findAllWithStream(
+2 -63
View File
@@ -37,11 +37,11 @@ class RecordingDataRaw {
return ret
}
async clearDeleted (index) {
async clearDeleted (index, where = { deleted: true }) {
const ret = await db[index + '_recording_data_raws'].destroy(
{
where: {
deleted: true
...where
}
}
)
@@ -103,67 +103,6 @@ class RecordingDataRaw {
return ret
}
// ref: https://stackoverflow.com/questions/47498083/find-the-closest-smaller-value-of-an-array
findClosestSmalllerValIndex (arr, val) {
const targetVal = arr.slice().reverse().find(e => e <= val) // why additionally use slice: see https://stackoverflow.com/questions/30610523/reverse-array-in-javascript-without-mutating-original-array
if (targetVal !== undefined) {
return arr.findIndex(e => e === targetVal)
} else {
return 0
}
}
async getSdDataByUUID (uuid, channel, startTime, endTime) {
const timeSlots = await this.getSdDataAllTimeslotByUUID(uuid, channel)
const startTimeArr = timeSlots.map(x => parseInt(x.start_time_sec) * 1e6 + parseInt(x.start_time_micro))
const endTimeArr = timeSlots.map(x => parseInt(x.end_time_sec) * 1e6 + parseInt(x.end_time_micro))
const startIndex = this.findClosestSmalllerValIndex(startTimeArr, parseInt(startTime))
let endIndex
const findEndIndex = endTimeArr.findIndex(el => el >= parseInt(endTime))
findEndIndex !== -1 ? endIndex = findEndIndex : endIndex = timeSlots.length - 1
const idList = timeSlots.slice(startIndex, endIndex + 1).map(x => x.id)
const ret = await db['sd_raw_neulive'].findAll(
{
where: {
id: idList
},
order: [
['start_time_sec', 'ASC'],
['start_time_micro', 'ASC']
],
raw: true,
}
)
return ret
}
async getSdDataAllTimeslotByUUID (uuid, channel) {
const ret = await db['sd_raw_neulive'].findAll(
{
where: {
parent_uuid: uuid,
channel: channel,
},
attributes: [
'id',
'start_time_sec',
'end_time_sec',
'start_time_micro',
'end_time_micro',
],
order: [
['start_time_sec', 'ASC'],
['start_time_micro', 'ASC']
],
raw: true,
}
)
return ret
}
async getByAttrID (id, attr, index) {
const attrList = attr.split('-')
const ret = await db[index + '_recording_data_raws'].findAll(
-42
View File
@@ -1,42 +0,0 @@
const db = require('../../db/database')
class SDRawNeulive {
async create (req) {
return db['sd_raw_neulive'].create(
req
)
}
async getByParentUUID (parent_uuid) {
const ret = await db['sd_raw_neulive'].findAllWithStream(
{
batchSize: 1000,
where: {
parent_uuid: parent_uuid
},
order: [
['id', 'ASC']
],
attributes: [
'data',
'start_time',
'end_time'
]
}
)
return ret
}
async clearDeleted (parent_uuid) {
const ret = await db['sd_raw_neulive'].destroy(
{
where: {
parent_uuid: parent_uuid
}
}
)
return ret
}
}
export default SDRawNeulive
+13 -11
View File
@@ -31,6 +31,19 @@ class ControllerModel {
}
}
async updateByID (req, id) {
req.updated_at = db.Sequelize.literal('CURRENT_TIMESTAMP')
const ret = await db.controllers.update(
req,
{
where: {
id: id
}
}
)
return ret
}
async updateByAttr (req, attr, value) {
const whereObj = {}
const attrList = attr.split('-')
@@ -92,17 +105,6 @@ class ControllerModel {
return ret
}
async getByMqttId (mqttId) {
const ret = await db.controllers.findAll(
{
where: {
mqtt_id: mqttId
}
}
)
return ret
}
async getByAttr (attr, value) {
const whereObj = {}
const attrList = attr.split('-')
+13
View File
@@ -35,6 +35,19 @@ class DeviceModel {
}
}
async updateByID (req, id) {
req.updated_at = db.Sequelize.literal('CURRENT_TIMESTAMP')
const ret = await db.devices.update(
req,
{
where: {
id: id
}
}
)
return ret
}
async updateByMac (req, mac) {
req.updated_at = db.Sequelize.literal('CURRENT_TIMESTAMP')
const ret = await db.devices.update(
+97
View File
@@ -0,0 +1,97 @@
const db = require('../../db/database')
// const Op = db.Sequelize.Op
class ProjectModal {
async create (req) {
return db.projects.create(req)
}
async update (req, id) {
if (id != null) {
const ret = await db.projects.update(
req,
{
where: {
id: id
}
}
)
return ret
} else {
const ret = await db.projects.update(
req,
{
where: {}
}
)
return ret
}
}
async updateByAttr (req, attr, value) {
const whereObj = {}
const attrList = attr.split('-')
const valueList = value.split('-')
attrList.forEach((key, idx) => {
whereObj[key] = valueList[idx]
})
const ret = await db.projects.update(
req,
{
where: whereObj
}
)
return ret
}
async clearDeleted () {
const ret = await db.projects.destroy(
{
where: {
deleted: true
}
}
)
return ret
}
async getByID (id) {
const ret = await db.projects.findAll(
{
where: {
id: id
}
}
)
return ret
}
async getByAttr (attr, value) {
const attrList = attr.split('-')
const valueList = value.split('-')
const whereObj = {}
attrList.forEach((key, idx) => {
whereObj[key] = valueList[idx]
})
const ret = await db.projects.findAll(
{
where: whereObj
}
)
return ret
}
async getAll () {
const ret = await db.projects.findAll({
order: [
['created_at', 'ASC']
]
})
return ret
}
}
export default ProjectModal
-11
View File
@@ -1,11 +0,0 @@
import controllers from '../../controllers'
// '/api/analysis'
export default function (_prefix) {
const prefix = _prefix + '/analysis'
return [
['POST', prefix + '/spike_detect', controllers.analysis.spikeDetect],
['POST', prefix + '/iir_filter', controllers.analysis.IIRFliter]
]
}
-17
View File
@@ -1,17 +0,0 @@
import controllers from '../../controllers'
// '/api/controller'
export default function (_prefix) {
const prefix = _prefix + '/controller'
return [
['POST', prefix + '/create', controllers.controller.create],
['POST', prefix + '/update/:id', controllers.controller.update],
['POST', prefix + '/update_by_attr/:attr/:value', controllers.controller.updateByAttr],
['GET', prefix + '/get_by_name/:name', controllers.controller.getByName],
['GET', prefix + '/get_by_mqtt_id/:mqtt_id', controllers.controller.getByMqttId],
['GET', prefix + '/get_by_mac/:mac', controllers.controller.getByMac],
['GET', prefix + '/get_by_attr/:attr/:value', controllers.controller.getByAttr],
['GET', prefix + '/get/all', controllers.controller.getAll]
]
}
-17
View File
@@ -1,17 +0,0 @@
import controllers from '../../controllers'
// '/api/device'
export default function (_prefix) {
const prefix = _prefix + '/device'
return [
['POST', prefix + '/create', controllers.device.create],
['POST', prefix + '/update/:id', controllers.device.update],
['POST', prefix + '/update_by_mac/:mac', controllers.device.updateByMac],
['POST', prefix + '/update_by_attr/:attr/:value', controllers.device.updateByAttr],
['GET', prefix + '/clear_deleted/:id', controllers.device.clearDeleted],
['GET', prefix + '/get_by_mac/:mac', controllers.device.getByMac],
['GET', prefix + '/get_by_attr/:attr/:value', controllers.device.getByAttr],
['GET', prefix + '/get/all', controllers.device.getAll]
]
}
-20
View File
@@ -1,20 +0,0 @@
import controllers from '../../../controllers'
// '/api/file/collection'
export default function (_prefix) {
const prefix = _prefix + '/collection'
return [
['POST', prefix + '/create', controllers.collection.create],
['POST', prefix + '/update/:id', controllers.collection.update],
['GET', prefix + '/clear_deleted/:controller_id', controllers.collection.clearDeleted],
['GET', prefix + '/get_by_id/:id', controllers.collection.getByID],
['GET', prefix + '/get_by_name/:name/:controller_id', controllers.collection.getByName],
['GET', prefix + '/get_by_parent/:type/:parent', controllers.collection.getByParent],
['GET', prefix + '/get_by_parent_name/:type/:parent/:name', controllers.collection.getByParentName],
['GET', prefix + '/get/all/:controller_id', controllers.collection.getAll],
['GET', prefix + '/get_by_name/:name', controllers.collection.getByName],
['GET', prefix + '/get/all', controllers.collection.getAll],
['GET', prefix + '/clear_deleted', controllers.collection.clearDeleted]
]
}
-18
View File
@@ -1,18 +0,0 @@
import collection from './collection'
import meta from './meta'
import mini from './mini'
import raw from './raw'
import sdcard from './sdcard'
import trigger from './trigger'
export default function (_prefix) {
const prefix = _prefix + '/file'
return [
...collection(prefix),
...meta(prefix),
...mini(prefix),
...raw(prefix),
...sdcard(prefix),
...trigger(prefix)
]
}
-25
View File
@@ -1,25 +0,0 @@
import controllers from '../../../controllers'
// '/api/file/meta'
export default function (_prefix) {
const prefix = _prefix + '/meta'
return [
['POST', prefix + '/create', controllers.recordingDataMeta.create],
['POST', prefix + '/update/:id', controllers.recordingDataMeta.update],
['GET', prefix + '/clear_deleted/', controllers.recordingDataMeta.clearDeleted],
['GET', prefix + '/get_by_name/:name', controllers.recordingDataMeta.getByName],
['GET', prefix + '/get_by_uuid/:uuid', controllers.recordingDataMeta.getByUUID],
['GET', prefix + '/get_by_id/:id', controllers.recordingDataMeta.getByID],
['GET', prefix + '/get_by_path/:path', controllers.recordingDataMeta.getByPath],
['GET', prefix + '/get_by_parent/:type/:parent', controllers.recordingDataMeta.getByParent],
['GET', prefix + '/get_count_by_parent/:type/:parent', controllers.recordingDataMeta.getCountByParent],
['GET', prefix + '/get_by_parent_with_limit/:type/:parent/:limit/:offset/:order', controllers.recordingDataMeta.getByParentWithLimit],
['GET', prefix + '/get_by_attr_parent_with_limit/:type/:parent/:limit/:offset/:order/:attr', controllers.recordingDataMeta.getByAttrsParentWithLimit],
['GET', prefix + '/get_or_create_by_path/:path', controllers.recordingDataMeta.getOrCreateByPath],
['GET', prefix + '/get/all', controllers.recordingDataMeta.getAll],
// control system 3.0
['GET', prefix + '/get_meta_by_uuid/:uuid', controllers.recordingDataMeta.getMetaByUUID],
['GET', prefix + '/get_meta_all', controllers.recordingDataMeta.getMetaAll],
]
}
-18
View File
@@ -1,18 +0,0 @@
import controllers from '../../../controllers'
// '/api/file/mini'
export default function (_prefix) {
const prefix = _prefix + '/mini'
return [
['POST', prefix + '/create/:channel', controllers.recordingDataMini.create],
['POST', prefix + '/update/:channel/:id', controllers.recordingDataMini.update],
['GET', prefix + '/clear_deleted/:channel/:id', controllers.recordingDataMini.clearDeleted],
['GET', prefix + '/get_by_id/:channel/:id', controllers.recordingDataMini.getByID],
['GET', prefix + '/get_by_parent/:channel/:parent', controllers.recordingDataMini.getByParent],
['GET', prefix + '/get_attr_by_id/:channel/:id/:attr', controllers.recordingDataMini.getAttrByID],
['GET', prefix + '/get_attr_by_parent/:channel/:parent/:attr', controllers.recordingDataMini.getAttrByParent],
['GET', prefix + '/random/get_by_id/:channel/:id', controllers.recordingDataMini.getRandomDataByID],
['GET', prefix + '/mean/get_by_id/:channel/:id', controllers.recordingDataMini.getMeanDataByID]
]
}
-22
View File
@@ -1,22 +0,0 @@
import controllers from '../../../controllers'
// '/api/file/raw'
export default function (_prefix) {
const prefix = _prefix + '/raw'
return [
['POST', prefix + '/create/:channel', controllers.recordingDataRaw.create],
['POST', prefix + '/update/:channel/:id', controllers.recordingDataRaw.update],
['POST', prefix + '/update_sd_data/:channel/:id', controllers.recordingDataRaw.updateSdData],
['GET', prefix + '/clear_deleted/:channel/:id', controllers.recordingDataRaw.clearDeleted],
['GET', prefix + '/get_by_id/:channel/:id', controllers.recordingDataRaw.getByID],
['GET', prefix + '/get_by_ids/:channel/:id', controllers.recordingDataRaw.getByIDs],
['GET', prefix + '/get_data_by_id/:channel/:id', controllers.recordingDataRaw.getDataByID],
['GET', prefix + '/get_sd_data_by_uuid/:uuid/:channel/:startTime/:endTime', controllers.recordingDataRaw.getSdDataByUUID],
['GET', prefix + '/get_sd_data_all_timeslot_by_uuid/:uuid/:channel', controllers.recordingDataRaw.getSdDataAllTimeslotByUUID],
['GET', prefix + '/get_by_parent/:channel/:parent', controllers.recordingDataRaw.getByParent],
['GET', prefix + '/get_attr_by_id/:channel/:id/:attr', controllers.recordingDataRaw.getAttrByID],
['GET', prefix + '/get_attr_by_ids/:channel/:id/:attr', controllers.recordingDataRaw.getAttrByIDs],
['GET', prefix + '/get_attr_by_parent/:channel/:parent/:attr', controllers.recordingDataRaw.getAttrByParent]
]
}
-13
View File
@@ -1,13 +0,0 @@
import controllers from '../../../controllers'
// '/api/file/sdcard'
export default function (_prefix) {
const prefix = _prefix + '/sdcard'
return [
['GET', prefix + '/get', controllers.sdCard.getFileList],
['POST', prefix + '/exist', controllers.sdCard.exist],
['POST', prefix + '/upload', controllers.sdCard.uploadThenDelete],
// ['POST', prefix + '/delete', controllers.sdCard.deleted]
]
}
-10
View File
@@ -1,10 +0,0 @@
import controllers from '../../../controllers'
// '/api/file/trigger'
export default function (_prefix) {
const prefix = _prefix + '/trigger'
return [
['GET', prefix + '/get_raw_by_uuid/:parent_uuid', controllers.trigger.getRawTriggerByUUID],
]
}
-17
View File
@@ -1,17 +0,0 @@
import file from './file'
import project from './project'
import device from './device'
import controller from './controller'
import analysis from './analysis'
export default function (_prefix) {
const prefix = _prefix + '/api'
return [
...file(prefix),
...project(prefix),
...device(prefix),
...controller(prefix),
...analysis(prefix)
]
}
-8
View File
@@ -1,8 +0,0 @@
import task from './task'
export default function (_prefix) {
const prefix = _prefix + '/project'
return [
...task(prefix)
]
}
-15
View File
@@ -1,15 +0,0 @@
import controllers from '../../../controllers'
// '/api/task'
export default function (_prefix) {
const prefix = _prefix + '/task'
return [
['POST', prefix + '/create', controllers.task.create],
['POST', prefix + '/update/:id', controllers.task.update],
['POST', prefix + '/update_by_attr/:attr/:value', controllers.task.updateByAttr],
['GET', prefix + '/get_by_id/:id', controllers.task.getByID],
['GET', prefix + '/get_by_attr/:attr/:value', controllers.task.getByAttr],
['GET', prefix + '/get/all', controllers.task.getAll]
]
}
+116 -26
View File
@@ -1,35 +1,125 @@
import KoaRouter from 'koa-router'
import controllers from '../controllers'
import api from './api'
const router = new KoaRouter()
router
// .get('/public/get', function (ctx, next) {
// ctx.body = 'no access'
// })
// .all('/upload', controllers.upload)
// .get('/public/api/:name', controllers.api.Get)
// .post('/api/:name', controllers.api.Post)
// .put('/api/:name', controllers.api.Put)
// .del('/api/:name', controllers.api.Delete)
// .post('/auth/:action', controllers.auth.Post)
export default router
.get('/public/get', function (ctx, next) {
ctx.body = '禁止访问!'
})
.all('/upload', controllers.upload)
.get('/public/api/:name', controllers.api.Get)
.post('/api/:name', controllers.api.Post)
.put('/api/:name', controllers.api.Put)
.del('/api/:name', controllers.api.Delete)
.post('/auth/:action', controllers.auth.Post)
// user
.get('/public/auth/get_cookie', controllers.auth.getCookie)
.get('/public/auth/update_license', controllers.auth.updateLicense)
.get('/public/auth/check_license', controllers.auth.checkLicense)
for (const _route of api('')) {
switch (_route[0]) {
case 'GET':
router.get(_route[1], _route[2])
break
case 'POST':
router.post(_route[1], _route[2])
break
default:
break
}
}
// collection
.post('/api/file/collection/create', controllers.collection.create)
.post('/api/file/collection/update/:id', controllers.collection.update)
.get('/api/file/collection/clear_deleted/:controller_id', controllers.collection.clearDeleted)
.get('/api/file/collection/get_by_id/:id', controllers.collection.getByID)
.get('/api/file/collection/get_by_name/:name/:controller_id', controllers.collection.getByName)
.get('/api/file/collection/get_by_parent/:type/:parent', controllers.collection.getByParent)
.get('/api/file/collection/get_by_parent_name/:type/:parent/:name', controllers.collection.getByParentName)
.get('/api/file/collection/get/all/:controller_id', controllers.collection.getAll)
export default router
.get('/api/file/collection/get_by_name/:name', controllers.collection.getByName)
.get('/api/file/collection/get/all', controllers.collection.getAll)
.get('/api/file/collection/clear_deleted/', controllers.collection.clearDeleted)
// meta
.post('/api/file/meta/create', controllers.recordingDataMeta.create)
.post('/api/file/meta/update/:id', controllers.recordingDataMeta.update)
.get('/api/file/meta/clear_deleted/', controllers.recordingDataMeta.clearDeleted)
.get('/api/file/meta/get_by_name/:name', controllers.recordingDataMeta.getByName)
.get('/api/file/meta/get_by_uuid/:uuid', controllers.recordingDataMeta.getByUUID)
.get('/api/file/meta/get_by_id/:id', controllers.recordingDataMeta.getByID)
.get('/api/file/meta/get_by_path/:path', controllers.recordingDataMeta.getByPath)
.get('/api/file/meta/get_by_parent/:type/:parent', controllers.recordingDataMeta.getByParent)
.get('/api/file/meta/get_attr_by_parent/:type/:parent/:attr', controllers.recordingDataMeta.getAttrByParent)
.get('/api/file/meta/get_count_by_parent/:type/:parent', controllers.recordingDataMeta.getCountByParent)
.get('/api/file/meta/get_by_parent_with_limit/:type/:parent/:limit/:offset/:order', controllers.recordingDataMeta.getByParentWithLimit)
.get('/api/file/meta/get_by_attr_parent_with_limit/:type/:parent/:limit/:offset/:order/:attr', controllers.recordingDataMeta.getByAttrsParentWithLimit)
.get('/api/file/meta/get_or_create_by_path/:path', controllers.recordingDataMeta.getOrCreateByPath)
.get('/api/file/meta/get/all', controllers.recordingDataMeta.getAll)
// raw
.post('/api/file/raw/create/:channel', controllers.recordingDataRaw.create)
.post('/api/file/raw/update/:channel/:id', controllers.recordingDataRaw.update)
.post('/api/file/raw/update_sd_data/:channel/:id', controllers.recordingDataRaw.updateSdData)
.get('/api/file/raw/clear_deleted/:channel/:id', controllers.recordingDataRaw.clearDeleted)
.get('/api/file/raw/get_by_id/:channel/:id', controllers.recordingDataRaw.getByID)
.get('/api/file/raw/get_by_ids/:channel/:id', controllers.recordingDataRaw.getByIDs)
.get('/api/file/raw/get_data_by_id/:channel/:id', controllers.recordingDataRaw.getDataByID)
.get('/api/file/raw/get_by_parent/:channel/:parent', controllers.recordingDataRaw.getByParent)
.get('/api/file/raw/get_attr_by_id/:channel/:id/:attr', controllers.recordingDataRaw.getAttrByID)
.get('/api/file/raw/get_attr_by_ids/:channel/:id/:attr', controllers.recordingDataRaw.getAttrByIDs)
.get('/api/file/raw/get_attr_by_parent/:channel/:parent/:attr', controllers.recordingDataRaw.getAttrByParent)
.get('/api/file/raw/get_csv/:id/:mode/:x_channel/:y_channel', controllers.recordingDataRaw.getCSV)
// mini
.post('/api/file/mini/create/:channel', controllers.recordingDataMini.create)
.post('/api/file/mini/update/:channel/:id', controllers.recordingDataMini.update)
.get('/api/file/mini/clear_deleted/:channel/:id', controllers.recordingDataMini.clearDeleted)
.get('/api/file/mini/get_by_id/:channel/:id', controllers.recordingDataMini.getByID)
.get('/api/file/mini/get_exist_or_not_by_id/:channel/:id', controllers.recordingDataMini.getExistOrNotByID)
.get('/api/file/mini/get_by_parent/:channel/:parent', controllers.recordingDataMini.getByParent)
.get('/api/file/mini/get_attr_by_id/:channel/:id/:attr', controllers.recordingDataMini.getAttrByID)
.get('/api/file/mini/get_attr_by_parent/:channel/:parent/:attr', controllers.recordingDataMini.getAttrByParent)
.get('/api/file/mini/random/get_by_id/:channel/:id', controllers.recordingDataMini.getRandomDataByID)
.get('/api/file/mini/mean/get_by_id/:channel/:id', controllers.recordingDataMini.getMeanDataByID)
// device
.post('/api/device/create', controllers.device.create)
.post('/api/device/update/:id', controllers.device.update)
.post('/api/device/update/all', controllers.device.update)
.post('/api/device/update_by_id/:id', controllers.device.updateByID)
.post('/api/device/update_by_mac/:mac', controllers.device.updateByMac)
.post('/api/device/update_by_attr/:attr/:value', controllers.device.updateByAttr)
.get('/api/device/clear_deleted/:id', controllers.device.clearDeleted)
.get('/api/device/get_by_mac/:mac', controllers.device.getByMac)
.get('/api/device/get_by_attr/:attr/:value', controllers.device.getByAttr)
.get('/api/device/get/all', controllers.device.getAll)
.post('/api/device/update_by_id/:id', controllers.device.updateByID)
.post('/api/device/update', controllers.device.update)
// controller
.post('/api/controller/create', controllers.controller.create)
.post('/api/controller/update/:id', controllers.controller.update)
.post('/api/controller/update/all', controllers.controller.update)
.post('/api/controller/update_by_attr/:attr/:value', controllers.controller.updateByAttr)
.get('/api/controller/get_by_mac/:mac', controllers.controller.getByMac)
.get('/api/controller/get_by_attr/:attr/:value', controllers.controller.getByAttr)
.get('/api/controller/get/all', controllers.controller.getAll)
.post('/api/controller/update_by_id/:id', controllers.controller.updateByID)
.post('/api/controller/update', controllers.controller.update)
// task
.post('/api/task/create', controllers.task.create)
.post('/api/task/update/:id', controllers.task.update)
.post('/api/task/update_by_attr/:attr/:value', controllers.task.updateByAttr)
.post('/api/task/update/all', controllers.task.update)
.get('/api/task/get_by_id/:id', controllers.task.getByID)
.get('/api/task/get_by_attr/:attr/:value', controllers.task.getByAttr)
.get('/api/task/get/all', controllers.task.getAll)
.post('/api/task/update', controllers.task.update)
.post('/api/task/update_by_id/:id', controllers.task.updateByID)
// analyze
.post('/api/analysis/spike_detect', controllers.analysis.spikeDetect)
// project
.post('/api/project/create', controllers.project.create)
.post('/api/project/update/:id', controllers.project.update)
.post('/api/project/update_by_attr/:attr/:value', controllers.project.updateByAttr)
.post('/api/project/update/all', controllers.project.update)
.get('/api/project/clear_deleted/:controller_id', controllers.project.clearDeleted)
.get('/api/project/get_by_id/:id', controllers.project.getByID)
.get('/api/project/get_by_attr/:attr/:value', controllers.project.getByAttr)
.get('/api/project/get/all', controllers.project.getAll)