Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Just a simple api server
## Config

- for configure api server use file config.yaml
- the cobfig file mast be located in the root folder with executable
- the config file must be located in the root folder with executable

```yaml
address: '127.0.0.1:8899' # self ip:port address where API service will be alvalible
Expand Down Expand Up @@ -122,7 +122,7 @@ services: # list of currently avalible API ser
- can be called by the API request
- json data can be passed as input parameters to the python script
- output of the script will be returned to the frontend in the json field "data"
- if script will be crushed with error, that error wil be returned to the frontend in the json field "errors"
- if the script crushed with an error, that error will be returned to the frontend in the json field "errors"

```python
import sys
Expand Down
31 changes: 0 additions & 31 deletions config.yaml
Original file line number Diff line number Diff line change
@@ -1,40 +1,9 @@
address: '0.0.0.0:8080' # self ip:port address where API service will be alvalible
services: # list of currently avalible API services
- database-sqlite: # internal unique API service name
name: 'database' # database instance name
type: sqlite # the type of the dattabase
path: 'database.sqlite' # path / ip:pot to the database file / host
user: root # database access user
pass: root # database access password
- database-sqlite1: # internal unique API service name
name: 'database1' # database instance name
type: sqlite # the type of the dattabase
path: 'database22.sqlite' # path / ip:pot to the database file / host
user: root # database access user
pass: root # database access password
- database-postgres:
name: 'db_postgres_test'
type: postgres
path: 'localhost:5432'
user: db_postgres_test
pass: db_postgres_test
# replaceNullWithDefault:
- database-postgres-crane-data-server:
name: 'crane_data_server'
type: postgres
path: 'localhost:5432'
user: crane_data_server
pass: 00d0-25e4-*&s2-ccds
# replaceNullWithDefault:
- py-test-script: # internal unique API service name
name: 'py-test' # the name of the python script (must be specified in the API request, field 'path')
type: python # the type of the service
path: 'extensions/scripts/script_tamplate.py' # the path to the python script file
user: root # can be used to restrict assecc to the python script
pass: root # can be used to restrict assecc to the python script
- executable-test-app: # internal unique API service name
name: 'executable-test' # the name of the exequtable (must be specified in the API request, field 'path')
type: bin # the type of the service
path: 'extensions/bin/simple-executable' # the path to the extension exequtable file
user: root # can be used to restrict assecc to the python script
pass: root # can be used to restrict assecc to the python script
27 changes: 27 additions & 0 deletions sql/1_create_user.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
USER
*/
-- Cleanup
DROP TABLE IF EXISTS app_user;
DROP TYPE IF EXISTS user_role_enum CASCADE;
-- Creation
do $$
begin
if not exists (SELECT 1 FROM pg_type WHERE typname = 'user_role_enum') THEN
create type user_role_enum AS ENUM ('admin','operator');
end if;
end
$$;
create table if not exists app_user (
id bigserial not null,
role user_role_enum not null,
name varchar(255) not null, --COMMENT 'ФИО Потльзователя',
login varchar(255) not null unique, --COMMENT ' Логин',
pass varchar(2584) not null, --COMMENT 'Пароль',
created timestamp not null default CURRENT_TIMESTAMP,
updated timestamp not null default CURRENT_TIMESTAMP,
deleted timestamp default null,
PRIMARY KEY (id, login)
);
comment on table app_user is 'Пользователи';
comment on column app_user.role is 'Признак группировки';
22 changes: 22 additions & 0 deletions sql/2_create_tag.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
PROCESS TAG
*/
-- Cleanup
DROP TABLE IF EXISTS tags;
DROP TYPE IF EXISTS tag_type_enum CASCADE;
-- Creation
do $$
begin
if not exists (SELECT 1 FROM pg_type WHERE typname = 'tag_type_enum') THEN
create type tag_type_enum as enum('Bool','Int','UInt','DInt','Word','LInt','Real','Time','Date_And_Time');
end if;
end
$$;
create table if not exists tags (
id serial not null,
type tag_type_enum not null, --COMMENT 'S7DataType(bool, int, uInt, dInt, word, lInt, real, time, dateAndTime)',
name varchar(255) not null unique, --COMMENT 'Имя тэга в системе',
description varchar(255) not null DEFAULT '', --COMMENT 'Дополнительная информация о тэге',
PRIMARY KEY (id)
);
comment on table tags is 'Справочник тэгов проекта.';
139 changes: 139 additions & 0 deletions sql/3_create_event.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
PROCESS EVENT
*/
-- Cleanup
DROP TRIGGER IF EXISTS event_insert_trigger ON event;
DROP TRIGGER IF EXISTS event_delete_trigger ON event;
DROP FUNCTION IF EXISTS event_purge_records();
DROP FUNCTION IF EXISTS event_check_for_purge();
DROP FUNCTION IF EXISTS event_counter_inc();
DROP FUNCTION IF EXISTS event_counter_dec();
DROP INDEX IF EXISTS idx_event_timestamp;
DROP TABLE IF EXISTS event;
DROP TABLE IF EXISTS event_utils;
-- Creation
CREATE TABLE IF NOT EXISTS event (
uid BIGSERIAL PRIMARY KEY, --'1.000000000000', --COMMENT 'Идентификатор записи',
timestamp TIMESTAMP NOT NULL,
pid int2 NOT NULL, --COMMENT 'Идентификатор тэга.',
value int2 NOT NULL, --COMMENT 'Значение тэга 0..255, аварийно если >0.',
status int2 NOT NULL --COMMENT 'DsStatus as 0..255',
);
comment on table event is 'События. Только тэги дискретных значений, регистрируется 0 - как норма, > 0 - как авария.';
CREATE INDEX idx_event_timestamp ON event (timestamp ASC);

CREATE TABLE
IF NOT EXISTS event_utils (
id SERIAL PRIMARY KEY,
row_count BIGINT,
row_limit BIGINT,
purge_batch_size INT,
purge_shift_size INT,
is_purge_running BOOLEAN
);

INSERT INTO
event_utils (
row_count,
row_limit,
purge_batch_size,
purge_shift_size,
is_purge_running
)
VALUES
(0, 6000000, 1000, 1000, 'f');

CREATE OR REPLACE FUNCTION event_purge_records()
RETURNS void
LANGUAGE plpgsql AS $$
DECLARE
deleted INT;
to_delete INT;
batch_size INT;
is_purge_possible BOOLEAN;
BEGIN
SELECT (row_count - row_limit + purge_shift_size), purge_batch_size
FROM event_utils INTO to_delete, batch_size;

WITH upd_result AS (
UPDATE event_utils SET is_purge_running = true WHERE id = 1 AND is_purge_running = false
RETURNING *
) SELECT count(*) = 1 FROM upd_result INTO is_purge_possible;

IF is_purge_possible THEN
deleted := 0;

WHILE (to_delete - deleted) > batch_size LOOP
WITH del_result AS (
DELETE FROM event
WHERE ctid IN (
SELECT ctid FROM event
ORDER BY timestamp, uid ASC
LIMIT batch_size
) RETURNING *
) SELECT (count(*) + deleted) FROM del_result into deleted;
END LOOP;

DELETE FROM event WHERE ctid IN (
SELECT ctid FROM event
ORDER BY timestamp, uid ASC
LIMIT (to_delete - deleted)
);

UPDATE event_utils SET is_purge_running = false WHERE id = 1;
END IF;
END;
$$;

CREATE OR REPLACE FUNCTION event_check_for_purge()
RETURNS void
LANGUAGE plpgsql
AS $$
DECLARE
is_purge_needed BOOLEAN;
BEGIN
SELECT row_count > row_limit FROM event_utils WHERE id = 1 INTO is_purge_needed;
IF is_purge_needed THEN
PERFORM event_purge_records();
END IF;
END;
$$;

CREATE OR REPLACE FUNCTION event_counter_inc()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
add_count INT;
BEGIN
SELECT count(*) FROM new_tbl INTO add_count;
UPDATE event_utils SET row_count = COALESCE(row_count, 0) + add_count WHERE id = 1;
PERFORM event_check_for_purge();
RETURN new;
END;
$$;

CREATE OR REPLACE TRIGGER event_insert_trigger
AFTER INSERT ON event
REFERENCING NEW TABLE AS new_tbl
FOR EACH STATEMENT
EXECUTE PROCEDURE event_counter_inc();

CREATE OR REPLACE FUNCTION event_counter_dec()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
del_count INT;
BEGIN
SELECT count(*) FROM old_tbl INTO del_count;
UPDATE event_utils SET row_count = COALESCE(row_count, 0) - del_count WHERE id = 1;
RETURN new;
END;
$$;

CREATE OR REPLACE TRIGGER event_delete_trigger
AFTER DELETE ON event
REFERENCING OLD TABLE AS old_tbl
FOR EACH STATEMENT
EXECUTE PROCEDURE event_counter_dec();
17 changes: 17 additions & 0 deletions sql/4_create_event_view.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-- Cleanup
DROP VIEW IF EXISTS event_view;
-- Creation
create or replace view event_view as
select
e.uid AS uid,
e.pid AS pid,
e.value AS value,
e.status AS status,
e.timestamp AS timestamp,
t.type AS type,
t.name AS name,
t.description AS description
from
(event e
left join tags t on
(e.pid = t.id));
60 changes: 60 additions & 0 deletions sql/5_create_operating_cycle.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
PROCESS OPERATING CYCLE
*/
-- Cleanup
DROP VIEW IF EXISTS operating_cycle_metric_value_view;
DROP TABLE IF EXISTS operating_cycle;
DROP TABLE IF EXISTS operating_cycle_metric;
DROP TABLE IF EXISTS operating_cycle_metric_value;
DROP TYPE IF EXISTS metric_data_type_enum CASCADE;
-- Creation
do $$
begin
if not exists (SELECT 1 FROM pg_type WHERE typname = 'metric_data_type_enum') THEN
create type metric_data_type_enum as enum('bool','int','real','time','date','timestamp','string');
end if;
end
$$;
create table operating_cycle (
id bigserial NOT NULL, -- 'Идентификатор записи рабочего цикла',
timestamp_start timestamp NOT NULL, --COMMENT 'Дата и время начала рабочего цикла',
timestamp_stop timestamp NOT NULL, --COMMENT 'Дата и время окончания рабочего цикла',
alarm_class char(2) NOT NULL, -- COMMENT 'Point alarm class as 0..15, 0 - no alarm',
PRIMARY KEY (id)
);
create table operating_cycle_metric (
id char(6) NOT NULL, --COMMENT 'Идентификатор метрики статистических значений рабочего цикла',
name varchar(255) NOT NULL, --COMMENT 'Имя метрики статистических значений рабочего цикла',
description varchar(255) NOT NULL, --COMMENT 'Имя метрики статистических значений рабочего цикла',
PRIMARY KEY (id)
--KEY name_idx1 (name)
);
insert into operating_cycle_metric (id, name, description) values
(1, 'average', 'Среднее арифметическое'),
(2, 'max', 'Максимальное'),
(3, 'min', 'Минимальное'),
(4, 'trip_count', 'Количество срабатываний'),
(5, 'diviation_max', 'Максимальное отклонение');
create table operating_cycle_metric_value (
operating_cycle_id int8 NOT NULL, --COMMENT 'Идентификатор записи рабочего цикла, к которрй относится данная хапись',
pid int4 NOT NULL, --COMMENT 'ID тэга',
metric_id char(6) NOT NULL, --COMMENT 'Идентификатор метрики рабочего цикла, к которрй относится данная хапись',
value decimal(16,8) NOT NULL, --COMMENT 'Значеник метрики',
PRIMARY KEY (operating_cycle_id, pid, metric_id)
);
create or replace view operating_cycle_metric_value_view as
select
ocmv.operating_cycle_id AS operating_cycle_id,
ocmv.pid AS "point_id",
tag.name AS point_name,
ocmv.metric_id AS "metric_id",
ocm."name" as metric_name,
ocmv.value AS value
-- tag.type AS type,
-- tag.description AS description
from
(operating_cycle_metric_value ocmv
left join tags tag on
(ocmv.pid = tag.id)
left join operating_cycle_metric ocm on
(ocmv.metric_id = ocm.id));
Loading