diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4441cf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/Data +/Public/data +__pycache__ +*.[Ss]ecrets.* +*.[Ss]ecret.* +/Python/pyodbc.py \ No newline at end of file diff --git a/Bash/NucelarMonitor.debian.execute.sh b/Bash/NucelarMonitor.debian.execute.sh new file mode 100755 index 0000000..8d0bb2b --- /dev/null +++ b/Bash/NucelarMonitor.debian.execute.sh @@ -0,0 +1,2 @@ +#!/bin/bash +nohup ./tu_script.sh > /dev/null 2>&1 & \ No newline at end of file diff --git a/Bash/NucelarMonitor.debian.script.sh b/Bash/NucelarMonitor.debian.script.sh new file mode 100755 index 0000000..0197c2d --- /dev/null +++ b/Bash/NucelarMonitor.debian.script.sh @@ -0,0 +1,160 @@ +#!/bin/bash + +# Settings. +key="kyman_9750h" +candle_seconds=10 +candle_sleep_seconds=1 +execute_sleep_seconds=0 +show_json=true +send_json=true +url_server="http://192.168.1.131:13000/debian" +# Settings. + +function get_net_data(){ + echo $(cat /proc/net/dev|tail -n +3|awk '{ + + interface = $1; + + gsub(/:/, "", interface); + array = "[\"" interface "\"," $2 "," $3 "," $4 "," $10 "," $11 "," $12 "]"; + + json = json == "" ? array : json "," array; + + }END{ + print "[" json "]"; + }') +} + +function execute(){ + + local domain=$(hostname -d) + local ips=$(ip -o addr|awk '{ + + is_ipv6 = $3 == "inet6" ? "true" : "false"; + + split($1, i, ":"); + split($4, ip, "/"); + + array = "[" i[1] ",\"" $2 "\"," is_ipv6 ",\"" ip[1] "\"," ip[2] "]"; + json = json == "" ? array : json "," array; + + }END{ + print "[" json "]"; + }') + local hostnames=$(hostname -A|awk '{ + json = json == "" ? "\"" $1 "\"" : json ",\"" $1 "\""; + }END{ + print "[" json "]"; + }') + local disks=$(lsblk -b -n -o name,size,fsavail,mountpoint|grep -E '└─|├─'|awk '{ + + device = $1; + total = $2; + available = $3 ~ /^\// || $3 == "" ? 0 : $3; + mountpoint = $4 != "" ? "\"" $4 "\"" : $3 ~ /^\// ? "null" : "\"" $3 "\""; + + gsub(/├─|└─/, "", device); + array = "[\"" device "\"," total "," available "," mountpoint "]"; + + json = json == "" ? array : json "," array; + + }END{ + print "[" json "]"; + }') + local iterations=0 + local cpu_in= + local cpu_out= + local cpu_minimum= + local cpu_maximum= + local cpu_average=0 + local memory_in= + local memory_out= + local memory_minimum= + local memory_maximum= + local memory_average=0 + local memory_total=$(cat /proc/meminfo|grep MemTotal:|awk '{print $2 * 1024}') + local limit_seconds=$(($(date +%s) + $candle_seconds)) + local json="[" + local net_data="[" + local candle_start=$(date +%s) + local candle_end= + + net_data=$net_data$(get_net_data) + + while true; do + + cpu=$(top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4}') + # memory=$(cat /proc/meminfo|grep MemFree:|awk '{print $2 * 1024}') + memory=$(cat /proc/meminfo|grep MemAvailable:|awk '{print $2 * 1024}') + + # cpu_average=$((cpu_average + cpu)) + # memory_average=$((memory_average + memory)) + cpu_average=$(echo "$cpu_average + $cpu"|bc -l) + memory_average=$(echo "$memory_average + $memory"|bc -l) + + cpu=${cpu/,/.} + + cpu_out=$cpu + memory_out=$memory + iterations=$((iterations + 1)) + + if [ -z "$cpu_in" ]; then + cpu_in=$cpu + memory_in=$memory + cpu_minimum=$cpu + cpu_maximum=$cpu + memory_minimum=$memory + memory_maximum=$memory + else + + if [ "$(echo "$cpu < $cpu_minimum"|bc -l)" -eq 1 ];then cpu_minimum=$cpu;fi + if [ "$(echo "$cpu > $cpu_maximum"|bc -l)" -eq 1 ];then cpu_maximum=$cpu;fi + if [ "$(echo "$memory < $memory_minimum"|bc -l)" -eq 1 ];then memory_minimum=$memory;fi + if [ "$(echo "$memory > $memory_maximum"|bc -l)" -eq 1 ];then memory_maximum=$memory;fi + # cpu_minimum=$(echo -e "$cpu_minimum\n$cpu" | sort -n | head -1) + # cpu_maximum=$(echo -e "$cpu_maximum\n$cpu" | sort -n | tail -1) + # memory_minimum=$(echo -e "$memory_minimum\n$memory" | sort -n | head -1) + # memory_maximum=$(echo -e "$memory_maximum\n$memory" | sort -n | tail -1) + + if [ $(date +%s) -ge $limit_seconds ]; then + break + fi + + sleep 1 + fi + done + + if [ -z "$domain" ]; then + domain="null" + else + domain="\"$domain\"" + fi + + # cpu_average=$((cpu_average / iterations)) + # memory_average=$((memory_average / iterations)) + cpu_average=$(echo "scale=6; $cpu_average / $iterations"|bc|awk '{printf $1 + 0}') + memory_average=$(echo "scale=6; $memory_average / $iterations"|bc|awk '{printf $1 + 0}') + + net_data="$net_data,$(get_net_data)]" + candle_end=$(date +%s) + + json="$json$hostnames,$domain,$ips,$disks,$iterations" + json="$json,[$candle_start,$candle_end]" + json="$json,[${cpu_in//,/.},${cpu_out//,/.},${cpu_minimum//,/.},${cpu_maximum//,/.},$cpu_average]" + json="$json,[$memory_total,$memory_in,$memory_out,$memory_minimum,$memory_maximum,$memory_average]" + json="$json,$net_data" + json="$json]" + + if [ "$show_json" = true ]; then echo "$json";fi + if [ "$send_json" = true ]; then + local response=$(echo "$json"|curl -s -X POST -H "Content-Type: application/json" -d @- "$url_server/$key") + fi + +} + +while true; do + execute + if [ $execute_sleep_seconds -gt 0 ]; then + sleep $execute_sleep_seconds + fi +done \ No newline at end of file diff --git a/Public/index.html b/Public/index.html new file mode 100644 index 0000000..dc09cc0 --- /dev/null +++ b/Public/index.html @@ -0,0 +1 @@ +

Funca

\ No newline at end of file diff --git a/Python/NucelarMonitor.py b/Python/NucelarMonitor.py new file mode 100644 index 0000000..0673506 --- /dev/null +++ b/Python/NucelarMonitor.py @@ -0,0 +1,738 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +import datetime +from typing import Any, Optional, Sequence, Self, Callable +from re import compile as re_compile, Pattern as REPattern, Match as REMatch, IGNORECASE as RE_IGNORE_CASE +from pyodbc import connect as pyodbc_connect +from socket import socket as Socket, AF_INET as ADDRESS_FAMILY_IPV4, SOCK_STREAM as SOCKET_STREAM, SOL_SOCKET as SOCKET_LAYER, SO_REUSEADDR as SOCKET_REUSE_ADDRESS +from inspect import stack as get_stack, FrameInfo +from traceback import format_stack as trace_format_stack, extract_tb as extract_traceback +from threading import Thread +from os.path import exists as path_exists, dirname as directory_name, abspath as absolute_path +from json import loads as json_decode, dumps as json_encode +from mimetypes import guess_type as get_mime_by_extension + +class NucelarMonitor: + + DEFAULT_SETTINGS:dict[str, Any|None] = { + "autostart" : True, + "print_format" : "[{type}] {yyyy}{mm}{dd} {hh}{ii}{ss} [{line}]{file}({method}): {message}", + "exception_format" : " '[{line}]{file}({method})'{lines}\n\n{exception_message}", + "print_types" : [ + ["unkn", "unknown"], + ["info", "information"], + ["warn", "warning"], + ["erro", "error", "wrong", "failure", "fail", "no"], + ["exce", "exception", "except"], + [" ok ", "ok", "success", "succeed", "yes"], + ["test", "debug"] + ], + "http_host" : "0.0.0.0", + "http_port" : 13000, + "http_cache_size" : 1024, + "http_maximum_connections" : 5, + "http_header_response" : ( + "{http_protocol}/{http_version} {http_code} {http_message}\r\n" + + "Content-Type: {mime}\r\n" + + "Content-Length: {length}\r\n" + + "\r\n" + ), + "http_protocol" : "HTTP", + "http_version" : "1.1", + "http_code" : 200, + "http_message" : "OK", + "http_encoder" : "utf-8", + "index_files" : ("index.html", "index.htm"), + "sql_host" : "127.0.0.1", + "sql_port" : 1433, + "sql_user" : "sa", + "sql_password" : "password", + "sql_database" : "NucelarMonitor", + "default_controllers" : { + "get" : { + "/" : "/Public" + }, + "post" : { + "/debian/{key}" : "debian" + } + }, + "default_connections" : {} + } + DEFAULT_I18N:dict[str, dict[str, str|Sequence[str]]] = { + "english" : {} + } + ROOT:str = directory_name(absolute_path(__file__)) + SLASH:str = "/" if "/" in ROOT else "\\\\" + SPECIAL_REGULAR_EXPRESSION_CHARACTERS:dict[str, str] = { + "\r" : "r", + "\n" : "n", + "\t" : "t" + } + + RE_KEY:REPattern = re_compile(r'^[a-z_][a-z0-9_]*$', RE_IGNORE_CASE) + RE_STRING_VARIABLE:REPattern = re_compile(r'\{([a-z_][a-z0-9_]*)\}', RE_IGNORE_CASE) + RE_EXCEPTION:REPattern = re_compile(r'^\s*File "([^"]+)", line ([0-9]+), in ([^\n]+)(.*|[\r\n]*)*$') + RE_NEW_LINE:REPattern = re_compile(r'\r\n|[\r\n]') + RE_TO_SNAKE:REPattern = re_compile(r'[^a-zA-Z0-9]*([A-Z][A-Z0-9]*)|[^a-z0-9]+') + RE_HTTP_REQUEST:REPattern = re_compile(r'^([^\s]+)\s([^\s\?\#]+)(?:\?([^#]+))?(?:\#[^\s]+)?\s([^\/]+)\/([0-9\.]+)$') + RE_HEADER_LINE:REPattern = re_compile(r'^([^\:]+)\:(.+)$') + RE_HTTP_BLOCKS:REPattern = re_compile(r'((?:(?!(?:(?:\r\n){2}|\n{2}|\r{2}))(?:.|[\r\n]+))+)(?:(?:(?:\r\n){2}|\n{2}|\r{2})((?:.+|[\r\n]+)*))?') + RE_LAST_DIRECTORY:REPattern = re_compile(r'^(.*)[\/][^\/]*\/?$') + RE_SLASHES:REPattern = re_compile(r'[\\\/]+') + RE_TO_REGULAR_EXPRESSION:REPattern = re_compile(r'[\(\)\{\}\/\\\.\-\+\*\^\$\?\|\!\<\>\r\n\t]') + RE_ROUTE_KEY:REPattern = re_compile(r'\\\{([a-z_][a-z0-9_]*)\\\}', RE_IGNORE_CASE) + + class Request: + + def __init__(self:Self, data:bytes, encoder:str = "utf-8") -> None: + + self.method:str + self.request:str + self.value_get:str|None + self.variables_get:dict[str, str] + self.variables_post:dict[str, str] + self.protocol:str + self.protocol_version:str + self.body:str + self.variables_uri:dict[str, str] = {} + + header, body = (lambda header, body:( + NucelarMonitor.RE_NEW_LINE.split(str(header).strip()), body + ))(*NucelarMonitor.RE_HTTP_BLOCKS.match(data.decode(encoder)).groups()) + + ( + self.method, + self.request, + self.value_get, + self.variables_get, + self.protocol, + self.protocol_version + ) = (lambda method, request, variables, protocol, protocol_version:( + str(method).lower(), + request, + variables, + self.parse_variables(variables), + protocol, + protocol_version + ))(*NucelarMonitor.RE_HTTP_REQUEST.match(header[0]).groups()) + self.body = body + self.variables_post = self.parse_variables(body) + + def set_uri_variables(self:Self, keys:list[str], matches:REMatch) -> None: + + i:int + value:str + + for i, value in enumerate(matches.groups()): + self.variables_uri[keys[i]] = value + + def get(self:Self, keys:str|Sequence[str], default:Optional[Any] = None) -> Any|None: + return NucelarMonitor.get_value(keys, ( + self.variables_uri, self.variables_get, self.variables_post + ), default) + + @classmethod + def parse_variables(cls:type[Self], string:Optional[str]) -> dict[str, str]: + if not string: + return {} + + variables:dict[str, str] = {} + pair:str + + for pair in string.split("&"): + if "=" in pair: + key, value = pair.split("=", 1) + variables[cls.to_snake(key)] = value + else: + variables[cls.to_snake(pair)] = "" + + return variables + + @staticmethod + def to_snake(string:str) -> str: + + def callback(matches:REMatch) -> str: + + upper:str|None = matches.group(1) + + return "_" + upper.lower() if upper else "_" + + return NucelarMonitor.RE_TO_SNAKE.sub(callback, string).lower() + + class Response: + + def __init__(self:Self, + nucelar_monitor:type[Self], + response:Optional[Any] = None, + mime:Optional[str] = None, + code:Optional[int] = None, + message:Optional[str] = None + ) -> None: + + default_code:int + default_message:str + + self.nucelar_monitor:NucelarMonitor = nucelar_monitor + default_code, default_message = self.nucelar_monitor.get_http_default_code() + self.body:bytes = b"" + self.mime:str + self.code:str = code or default_code + self.message:str = default_message if message is None else message + + self.set_data(response, mime) + + def set_data(self:Self, data:Any|None, mime:Optional[str] = None) -> None: + if isinstance(data, bytes): + self.body = data + self.mime = mime or "application/octet-stream" + elif isinstance(data, str): + self.body = data.encode(self.nucelar_monitor.get_encoder()) + self.mime = mime or "text/plain;charset=" + self.nucelar_monitor.get_encoder() + elif isinstance(data, (dict, tuple, list)): + self.body = json_encode(data).encode(self.nucelar_monitor.get_encoder()) + self.mime = mime or "application/json;charset=" + self.nucelar_monitor.get_encoder() + else: + self.body = str(data).encode(self.nucelar_monitor.get_encoder()) + self.mime = mime or "text/plain;charset=" + self.nucelar_monitor.get_encoder() + + def get_parameters(self:Self) -> dict[str, Any|None]: + return { + "http_code" : self.code, + "http_message" : self.message, + "mime" : self.mime, + "length" : len(self.body) + } + + def __init__(self:Self, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None: + + key:str + + self.__inputs:dict[str, Any|None] = self.get_dictionary(inputs) + self.__sentences:dict[str, dict[str, str|Sequence[str]]] = self.DEFAULT_I18N + self.__language:str = self.get("language", None, "english") + self.__print_format:str = self.get("print_format") + self.__print_types:list[list[str]] = self.DEFAULT_SETTINGS["print_types"] + self.__exception_format:str = self.get("exception_format") + self.__controllers:dict[str, list[tuple[ + REPattern, + tuple[tuple[str, ...]], + Callable[[NucelarMonitor.Request, NucelarMonitor.Response], None]|None, + str|None] + ]] = {} + self.__http_host:str = self.get("http_host") + self.__http_port:int = self.get("http_port") + self.__http_server:Socket + self.__http_buffer_size:int = self.get("http_cache_size") + self.__http_header_response:str = self.get("http_header_response") + self.__http_protocol:str = self.get("http_protocol") + self.__http_version:str = self.get("http_version") + self.__http_code:int = self.get("http_code") + self.__http_message:str = self.get("http_message") + self.__http_encoder:str = self.get("http_encoder") + self.__index_files:tuple[str, ...] = tuple(self.get("index_files")) + self.__started:bool = False + self.__working:bool = False + self.__root_paths:list[str] = ["", self.ROOT] + + for _ in range(2): + self.__root_paths.append(self.RE_LAST_DIRECTORY.sub(r'\1', self.__root_paths[-1])) + + for key in ("default_controllers", "controllers"): + self.add_controllers(self.get(key)) + + self.get("autostart") and self.start() + + def start(self:Self) -> None: + if self.__started: + return + self.__started = True + + self.__http_server = Socket(ADDRESS_FAMILY_IPV4, SOCKET_STREAM) + self.__working = True + + try: + + self.__http_server.setsockopt(SOCKET_LAYER, SOCKET_REUSE_ADDRESS, 1) + self.__http_server.bind((self.__http_host, self.__http_port)) + self.__http_server.listen(self.get("http_maximum_connections")) + + Thread(target = self.__listen).start() + + except Exception as exception: + self.exception(exception, "http_server_start_exception", { + "host" : self.__http_host, + "port" : self.__http_port, + }) + self.close() + + def close(self:Self) -> None: + if not self.__started: + return + + self.__started = False + self.__working = False + + try: + self.__http_server.close() + except Exception as exception: + self.exception(exception, "http_server_close_exception", { + "host" : self.__http_host, + "port" : self.__http_port, + }) + + def get_print_type(self:Self, _type:str) -> str: + + group:list[str] + + for group in self.__print_types: + if _type in group: + return group[0].upper() + return self.__print_types[0][0].upper() + + def print(self:Self, + _type:str, + message:str|Sequence[str], + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None, + i:int = 0 + ) -> None: + + date:datetime = datetime.datetime.now() + own:dict[str, Any|None] = { + "raw_type" : _type, + "type" : self.get_print_type(_type), + "i18n" : self.get_texts(message), + "message" : self.i18n(message, inputs), + **self.get_dictionary(inputs), + **self.get_action_data(i + 1) + } + + for key in ("year", "month", "day", "hour", "minute", "second"): + + k:str = "i" if key == "minute" else key[0] + + own[k] = own[key] = getattr(date, key) + own[k + k] = ("00" + str(own[key]))[-2:] + + own["yyyy"] = own["year"] + + print(self.string_variables(self.__print_format, own) + (own["end"] if "end" in own else "")) + + def exception(self:Self, + exception:Exception, + message:str|Sequence[str], + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None, + i:int = 0 + ) -> None: + + lines:list[str] = extract_traceback(exception.__traceback__).format() + matches:REMatch = self.RE_EXCEPTION.match(lines[-1]) + data:dict[str, Any|None] = { + **self.get_dictionary(inputs), + "lines" : "", + "exception_message" : str(exception), + "method" : matches.group(3), + "line" : matches.group(2), + "file" : matches.group(1) + } + block:str + j:int + + for j, block in enumerate(trace_format_stack()[:-2] + lines): + if block: + data["lines"] += "\n " + str(j) + " - " + self.RE_NEW_LINE.split(block.strip())[0] + + data["end"] = self.string_variables(self.__exception_format, data) + + message and self.print("exception", message, data, i + 2) + + @classmethod + def fix_path(cls:type[Self], path:str) -> str: + return cls.RE_SLASHES.sub(cls.SLASH, path) + + def get_absolute_path(self:Self, path:str) -> str|None: + + root:str + absolute:str + + for root in self.__root_paths: + absolute = self.fix_path(root + '/' + path) + if path_exists(absolute): + return absolute + return None + + def load_file(self:Self, path:str, mode:str = "r") -> str|bytes|None: + + path:str = self.get_absolute_path(path) + + if path: + with open(path, mode) as file: + return file.read() + return None + + def load_json(self:Self, data:str|dict[str, Any|None]|list[Any|None]) -> dict[str, Any|None]|list[Any|None]|None: + if isinstance(data, str): + + json:list[Any|None]|dict[str, Any|None]|None + + try: + json = json_decode(data) + except Exception as exception: + self.exception(exception, "load_json_exception", { + "data" : data, + "length" : len(data) + }) + + if json: + return json + try: + return json_decode(self.load_file(data)) + except Exception as exception: + self.exception(exception, "load_json_by_file_exception", { + "path" : data + }) + return None + elif isinstance(data, (dict, list)): + return data + return None + + def get_encoder(self:Self) -> str: + return self.__http_encoder + + def get_http_default_code(self:Self) -> tuple[int, str]: + return self.__http_code, self.__http_message + + def get(self:Self, + keys:str|Sequence[str], + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None, + default:Optional[Any] = None + ) -> Any|None: + return self.get_value(keys, (inputs, self.__inputs, self.DEFAULT_SETTINGS), default) + + def __get_text(self:Self, strings:str|Sequence[str]) -> str: + + keys:list[str] = self.get_keys(strings := self.get_list(strings)) + + if len(keys): + + language:str + used:list[str] = [] + + for language in [self.__language] + list(self.__sentences.keys()): + if language not in used and language in self.__sentences: + + key:str + + used.append(language) + for key in keys: + if key in self.__sentences[language]: + return self.__sentences[language][key] + return strings[0] + + def i18n(self:Self, + strings:str|Sequence[str], + inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None + ) -> str: + return self.string_variables(self.__get_text(strings), inputs) + + def add_controllers(self:Self, + inputs:str|dict[str, dict[str, str|Callable[[Request], None]]]|Sequence[Any|None] + ) -> None: + if isinstance(inputs, dict): + + method:str + controllers:dict[str, str|Callable[[NucelarMonitor.Request], None]] + + for method, controllers in inputs.items(): + if (method := method.lower()) not in self.__controllers: + self.__controllers[method] = [] + if isinstance(controllers, dict): + + request:str + target:str|Callable[[NucelarMonitor.Request], None] + + for request, target in controllers.items(): + + controller:Callable[[NucelarMonitor.Request, NucelarMonitor.Response], None]|None = None + path:str|None = None + + if isinstance(target, str) and (controller := getattr(self, target, None)) is None: + path = self.get_absolute_path(target) + + if callable(controller) or path is not None: + + variables:list[str] = [] + + def callback(matches:REMatch) -> str: + + variables.append(matches.group(1)) + + return r'([^\/]+)' + + self.__controllers[method].append((re_compile(r'^' + self.RE_ROUTE_KEY.sub(callback, self.to_regular_expression( + request[:-1] if request[-1] == "/" else request + )) + (r'' if path is None else r'(.*)') + r'\/?$'), tuple(variables), controller, path)) + + elif isinstance(inputs, (list, tuple)): + + subinputs:Any|None + + for subinputs in inputs: + self.add_controllers(subinputs) + + elif isinstance(inputs, str): + self.add_controllers(self.load_json(inputs)) + + def __listen(self:Self) -> None: + while self.__working: + try: + + client:Socket + address:str + port:int + + client, (address, port) = self.__http_server.accept() + + Thread( + target = self.__listen_client, + args = (client, address, port) + ).start() + + except Exception as exception: + self.exception(exception, "http_server_listen_exception", { + "host" : self.__http_host, + "port" : self.__http_port, + }) + + def __listen_client(self:Self, client:Socket, address:str, port:int) -> None: + + data:bytes = b"" + route:str = "" + method:str = "UNKN" + response:NucelarMonitor.Response = NucelarMonitor.Response(self) + + try: + + request:NucelarMonitor.Request + variables:tuple[str, ...] + controller:Callable[[NucelarMonitor.Request], Any|None]|None + path:str|None + response_data:Any|None = None + pattern:REPattern + done:bool = False + + while True: + + buffer:bytes = client.recv(self.__http_buffer_size) + + if not buffer: + break + data += buffer + if len(buffer) != self.__http_buffer_size: + break + + for pattern, variables, controller, path in self.__controllers[ + method := (request := self.Request(data, self.__http_encoder)).method + ]: + + matches:REMatch = pattern.match(route := request.request) + + if matches is not None: + request.set_uri_variables(variables, matches) + if done := path is not None: + for index in self.__index_files: + + full_path = path + "/" + route + ("" if index == "" else "/" + index) + + if done := (response_data := self.load_file(full_path, "rb")) is not None: + response.set_data( + response_data, + get_mime_by_extension(full_path)[0] or "application/octet-stream" + ) + break + + elif done := controller is not None: + controller(request, response) + + if done: + break + + + if not done: + response.body = b"

Not Found

" + response.mime = "text/html;charset=" + self.__http_encoder + response.code = "404" + response.message = "Not Found" + + client.sendall(self.string_variables(self.__http_header_response, { + "http_protocol" : self.__http_protocol, + "http_version" : self.__http_version, + **response.get_parameters() + }).encode(self.__http_encoder) + response.body) + client.close() + + except Exception as exception: + self.exception(exception, "http_server_client_exception", { + "host" : self.__http_host, + "port" : self.__http_port, + "client_address" : address, + "client_port" : port, + "length" : len(data), + "method" : method, + "route" : route, + "response_length" : len(response.body) + }) + + def debian(self:Self, request:Request, response:Response) -> None: + + key:str = request.get("key") + hostnames:list[str] + domain:str|None + interfaces:list[list[int, str, bool, str, int]] + disks:list[list[str, int, int, str|None]] + iterations:int + candle_times:list[int, int] + cpu:list[float, float, float, float, float] + memory:list[int, int, int, int, int, float] + net_use:list[list[list[str, int, int, int, int, int, int]]] + + hostnames, domain, interfaces, disks, iterations, candle_times, cpu, memory, net_use = json_decode(request.body) + + @classmethod + def get_dictionary(cls:type[Self], *items:Sequence[Any|None]) -> dict[str, Any|None]: + + dictionary:dict[str, Any|None] = {} + item:Any|None + + for item in items: + if isinstance(item, dict): + dictionary.update(item) + elif isinstance(item, (list, tuple)): + + subitem:Any|None + + for subitem in item: + dictionary.update(cls.get_dictionary(subitem)) + + return dictionary + + @classmethod + def get_keys(cls:type[Self], *items:Sequence[Any|None]) -> list[str]: + + keys:list[str] = [] + item:Any|None + + for item in items: + if isinstance(item, str): + cls.RE_KEY.match(item) and keys.append(item) + elif isinstance(item, (list, tuple)): + + subitem:Any|None + + for subitem in item: + keys.extend(cls.get_keys(subitem)) + + return keys + + @classmethod + def get_dictionaries(cls:type[Self], *items:Sequence[Any|None]) -> list[dict[str, Any|None]]: + + dictionaries:list[dict[str, Any|None]] = [] + item:Any|None + + for item in items: + if isinstance(item, dict): + dictionaries.append(item) + elif isinstance(item, (list, tuple)): + + subitem:Any|None + + for subitem in item: + dictionaries.extend(cls.get_dictionaries(subitem)) + + return dictionaries + + @classmethod + def get_value(cls:type[Self], + keys:str|Sequence[str], + inputs:dict[str, Any|None]|Sequence[Any|None], + default:Optional[Any] = None + ) -> Any|None: + if len(cls.get_keys(keys)): + + dictionary:dict[str, Any|None] + + for dictionary in cls.get_dictionaries(inputs): + + key:str + + for key in cls.get_keys(keys): + if key in dictionary: + return dictionary[key] + return default + + @staticmethod + def get_list(item:Any|None) -> list[Any|None]: + return item if isinstance(item, (list, tuple)) else [item] + + @classmethod + def string_variables(cls:type[Self], + string:str, + inputs:dict[str, Any|None]|Sequence[Any|None], + default:Optional[str] = None + ) -> str: + + variables:dict[str, Any|None] = cls.get_dictionary(inputs) + + def callback(matches:REMatch) -> str: + + key:str = matches.group(1) + + return ( + str(variables[key]) if key in variables else + default if default is not None else + matches.group(0)) + + return cls.RE_STRING_VARIABLE.sub(callback, string) + + @staticmethod + def get_texts(*items:list[Any|None]) -> list[str]: + + texts:list[str] = [] + item:Any|None + + for item in items: + if isinstance(item, str): + texts.append(item) + elif isinstance(item, (list, tuple)): + + subitem:Any|None + + for subitem in item: + texts.extend(NucelarMonitor.get_texts(subitem)) + + return texts + + @staticmethod + def get_action_data(i:int = 0) -> dict[str, str|int]: + + stack:FrameInfo = get_stack()[i] + + return { + "file" : stack.filename, + "method" : stack.function, + "line" : stack.lineno + } + + @classmethod + def to_regular_expression(cls:type[Self], string:str) -> str: + + def callback(matches:REMatch) -> str: + + character:str = matches.group(0) + + return "\\" + ( + cls.SPECIAL_REGULAR_EXPRESSION_CHARACTERS[character] if character in cls.SPECIAL_REGULAR_EXPRESSION_CHARACTERS else + character) + + return cls.RE_TO_REGULAR_EXPRESSION.sub(callback, string) \ No newline at end of file diff --git a/Python/run.py b/Python/run.py new file mode 100644 index 0000000..df7d197 --- /dev/null +++ b/Python/run.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from NucelarMonitor import NucelarMonitor + +nucelar_monitor:NucelarMonitor = NucelarMonitor() \ No newline at end of file diff --git a/README.md b/README.md index b18c6f6..4449d1b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,48 @@ # NucelarMonitor -NucelarMonitor is a very single project for monitoring OS and their Hardware and services in Stream via Web from server. \ No newline at end of file +NucelarMonitor is a very single project for monitoring OS and their Hardware and services in Stream via Web from server. + +# Notes + +Datos de envío Debian: + +0. `list[str]`: Hostnames. +1. `str|None`: Domain. +2. `list[list[int, str, bool, str, int]]`: Interfaces de red. Por cada uno: + 0. `int`: i. Identificador de posición. + 1. `str`: Nombre. + 2. `bool`: ¿Es IPv6? + 3. `str`: IP. + 4. `int`: Máscara. +3. `list[list[str, int, int, str|None]]`: Discos. Por cada uno: + 0. `str`: Nombre. + 1. `int`: Capacidad. + 2. `int`: Espacio libre. + 3. `str|None`: Punto de montaje. +4. `int`: Iteraciones o ciclos de conteo de las velas. +5. `list[int, int]`: Timestamp de inicio y de fin de las velas. + 0. `int`: Timestamp de inicio. + 1. `int`: Timestamp de fin. +6. `list[float, float, float, float, float]`: Vela de uso porcentual de la CPU: + 0. `float`: Entrada. + 1. `float`: Salida. + 2. `float`: Mínimo. + 3. `float`: Máximo. + 4. `float`: Media. +7. `list[int, int, int, int, int, float]`: Vela de uso de la memoria RAM. + 0. `int`: Total de memoria. + 1. `int`: Entrada. + 2. `int`: Salida. + 3. `int`: Mínimo. + 4. `int`: Máximo. + 5. `float`: Media. +8. `list[list[list[str, int, int, int, int, int, int]]]`: Uso de Red. Está diseñado en un proceso de diferencia Entrada/Salida. Es una lista de dos listas, entrada y salida, el segundo nivel tiene una lista por cada interfaz de red, las cuales tienen: + 0. `str`: Nombre. Identifica la interfaz de red. + 1. `int`: Bytes recepcionados actualmente. + 2. `int`: Paquetes recepcionados actualmente. + 3. `int`: Errores en recepción actualmente. + 4. `int`: Bytes enviados actualmente. + 5. `int`: Paquetes enviados actualmente. + 6. `int`: Errores en envío actualmente. + +La idea es procesar el uso de red en Python. \ No newline at end of file diff --git a/SQLServer/NucelarMonitor.server.sql b/SQLServer/NucelarMonitor.server.sql new file mode 100644 index 0000000..f910665 --- /dev/null +++ b/SQLServer/NucelarMonitor.server.sql @@ -0,0 +1,609 @@ +if (select top 1 0 from sys.databases where name = 'NucelarMonitor') is null create database NucelarMonitor collate Latin1_General_100_CI_AS_SC_UTF8 +go +use NucelarMonitor + +if object_id(N'dbo.tables_drop', N'P') is not null drop procedure dbo.tables_drop +go +create procedure dbo.tables_drop as begin + + set nocount on + + -- Level Plains. + + -- Level 2. + if object_id(N'dbo.MachineInterfacesData', N'U') is not null drop table dbo.MachineInterfacesData + if object_id(N'dbo.MachineInterfacesTraffic', N'U') is not null drop table dbo.MachineInterfacesTraffic + if object_id(N'dbo.MachineDisksSpace', N'U') is not null drop table dbo.MachineDisksSpace + if object_id(N'dbo.Exceptions', N'U') is not null drop table dbo.Exceptions + + -- Level 1. + if object_id(N'dbo.MachineInterfaces', N'U') is not null drop table dbo.MachineInterfaces + if object_id(N'dbo.MachineDisks', N'U') is not null drop table dbo.MachineDisks + if object_id(N'dbo.MachineRAM', N'U') is not null drop table dbo.MachineRAM + if object_id(N'dbo.MachineCPU', N'U') is not null drop table dbo.MachineCPU + if object_id(N'dbo.Procedures', N'U') is not null drop table dbo.Procedures + + -- Level 0. + if object_id(N'dbo.CandlesTimes', N'U') is not null drop table dbo.CandlesTimes + if object_id(N'dbo.Interfaces', N'U') is not null drop table dbo.Interfaces + if object_id(N'dbo.Disks', N'U') is not null drop table dbo.Disks + if object_id(N'dbo.Hostnames', N'U') is not null drop table dbo.Hostnames + if object_id(N'dbo.Domains', N'U') is not null drop table dbo.Domains + if object_id(N'dbo.Machines', N'U') is not null drop table dbo.Machines + if object_id(N'dbo.Databases', N'U') is not null drop table dbo.Databases + if object_id(N'dbo.Messages', N'U') is not null drop table dbo.Messages + if object_id(N'dbo.BigData', N'U') is not null drop table dbo.BigData + +end +go + +if object_id(N'dbo.tables_create', N'P') is not null drop procedure dbo.tables_create +go +create procedure dbo.tables_create as begin + + set nocount on + + -- Level 0. + if object_id(N'dbo.Machines', N'U') is null create table dbo.Machines( + id integer not null identity(1, 1), + [key] varchar(32) not null, + [description] varchar(512), + date_in datetime not null constraint machines_df_date_in default getdate(), + date_out datetime, + constraint machines_pk primary key clustered (id), + constraint machines_uk_key unique ([key]), + constraint machines_ck_key check ([key] like '[a-zA-Z0-9][a-zA-Z0-9_]{0,31}') with (fillfactor = 90) + ) + + if object_id(N'dbo.Domains', N'U') is null create table dbo.Domains( + id integer not null identity(1, 1), + domain varchar(64) not null, + [description] varchar(512), + date_in datetime not null constraint domains_df_date_in default getdate(), + date_out datetime, + constraint domains_pk primary key clustered (id), + constraint domains_uk_domain unique nonclustered (domain asc) with (fillfactor = 90), + constraint domains_ck_domain check ([domain] like '[a-zA-Z0-9_-.]{1,64}') with (fillfactor = 90) + ) + + + if object_id(N'dbo.Hostnames', N'U') is null create table dbo.Hostnames( + id integer not null identity(1, 1), + [name] varchar(32) not null, + [description] varchar(512), + date_in datetime not null constraint hostnames_df_date_in default getdate(), + date_out datetime, + constraint hostnames_pk primary key clustered (id), + constraint hostnames_uk_name unique nonclustered ([name] asc) with (fillfactor = 90), + constraint hostnames_ck_name check ([name] like '[a-zA-Z0-9_-]{1,32}') with (fillfactor = 90) + ) + + if object_id(N'dbo.Disks', N'U') is null create table dbo.Disks( + id integer not null identity(1, 1), + [name] varchar(32) not null, + [size] bigint not null, + mountpoint varchar(128) not null, + [description] varchar(512), + date_in datetime not null constraint disks_df_date_in default getdate(), + date_out datetime, + constraint disks_pk primary key clustered (id), + constraint disks_uk_name unique nonclustered ([name] asc, mountpoint asc) with (fillfactor = 90), + constraint disks_ck_name check ( + [name] like '[a-zA-Z0-9_-]{1,32}' or + mountpoint like '[A-Z]:' + ) with (fillfactor = 90), + constraint disks_ck_size check (size >= 0 and size < power(2, 53)) with (fillfactor = 90), + constraint disks_ck_mountpoint check ( + mountpoint like '/%' or + mountpoint like '[a-zA-Z]:\%' or + mountpoint like '\\%' + ) with (fillfactor = 90) + ) + + if object_id(N'dbo.Interfaces', N'U') is null create table dbo.Interfaces( + id integer not null identity(1, 1), + [name] varchar(32) not null, + [description] varchar(512), + date_in datetime not null constraint interfaces_df_date_in default getdate(), + date_out datetime, + constraint interfaces_pk primary key clustered (id), + constraint interfaces_uk_machine_name unique nonclustered (machine asc, [name] asc) with (fillfactor = 90), + constraint interfaces_ck_name check ([name] like '[a-zA-Z0-9_-]{1,32}') with (fillfactor = 90) + ) + + if object_id(N'dbo.CandlesTimes', N'U') is null create table dbo.CandlesTimes( + id integer not null identity(1, 1), + [from] datetime not null, + [to] datetime not null, + date_in datetime not null constraint candles_times_df_date_in default getdate(), + date_out datetime, + constraint candles_times_pk primary key clustered (id), + constraint candles_times_uk_from_to unique nonclustered ([from] asc, [to] asc) with (fillfactor = 90), + constraint candles_times_ck_from_to check ([from] < [to]) with (fillfactor = 90) + ) + + if object_id(N'dbo.BigData', N'U') is null create table dbo.BigData( + id integer not null identity(1, 1), + [hash] binary(64) not null, + [value] varchar(max) not null, + date_in datetime not null constraint big_data_df_date_in default getdate(), + date_out datetime, + constraint big_data_pk primary key clustered (id), + constraint big_data_uk_hash unique nonclustered ([hash] asc) with (fillfactor = 90) + ) + + if object_id(N'dbo.Messages', N'U') is null create table dbo.Messages( + id integer not null identity(1, 1), + [key] varchar(128) not null, + date_in datetime not null constraint messages_df_date_in default getdate(), + date_out datetime, + constraint messages_pk primary key clustered (id), + constraint messages_ck_key check ([key] like '[a-zA-Z_][a-zA-Z0-9_]{0,127}') with (fillfactor = 90) + ) + + if object_id(N'dbo.Databases', N'U') is null create table dbo.Databases( + id integer not null identity(1, 1), + [name] varchar(64) not null, + date_in datetime not null constraint databases_df_date_in default getdate(), + date_out datetime, + constraint databases_pk primary key clustered (id), + constraint databases_uk_name unique nonclustered ([name] asc) with (fillfactor = 90), + constraint databases_ck_name check ([name] like '[a-zA-Z_][a-zA-Z0-9_]{0,63}') with (fillfactor = 90) + ) + + -- Level 1. + if object_id(N'dbo.MachineCPU', N'U') is null create table dbo.MachineCPU( + id integer not null identity(1, 1), + machine integer not null, + candle_time integer not null, + [in] float not null, + [out] float not null, + minimum float not null, + maximum float not null, + average float not null, + date_in datetime not null constraint machine_cpu_df_date_in default getdate(), + date_out datetime, + constraint machine_cpu_pk primary key clustered (id), + constraint machine_cpu_fk_machine foreign key (machine) references dbo.Machines(id) + on update no action + on delete no action, + constraint machine_cpu_fk_candle_time foreign key (candle_time) references dbo.CandlesTimes(id) + on update no action + on delete no action, + constraint machine_cpu_ck_cpu_in check ( + [in] between 0 and 100 and + [in] between minimum and maximum + ) with (fillfactor = 90), + constraint machine_cpu_ck_cpu_out check ( + [out] between 0 and 100 and + [out] between minimum and maximum + ) with (fillfactor = 90), + constraint machine_cpu_ck_cpu_minimum check ( + minimum between 0 and 100 and + minimum <= maximum + ) with (fillfactor = 90), + constraint machine_cpu_ck_cpu_maximum check ( + maximum between 0 and 100 and + maximum >= minimum + ) with (fillfactor = 90), + constraint machine_cpu_ck_cpu_average check ( + average between 0 and 100 and + average between minimum and maximum + ) with (fillfactor = 90) + ) + + if object_id(N'dbo.MachineRAM', N'U') is null create table dbo.MachineRAM( + id integer not null identity(1, 1), + machine integer not null, + candle_time integer not null, + total bigint not null, + [in] bigint not null, + [out] bigint not null, + minimum bigint not null, + maximum bigint not null, + average bigint not null, + date_in datetime not null constraint machine_ram_df_date_in default getdate(), + date_out datetime, + constraint machine_ram_pk primary key clustered (id), + constraint machine_ram_fk_machine foreign key (machine) references dbo.Machines(id) + on update no action + on delete no action, + constraint machine_ram_fk_candle_time foreign key (candle_time) references dbo.CandlesTimes(id) + on update no action + on delete no action, + constraint machine_ram_ck_memory_total check ( + total between 0 and power(2, 53) - 1 + ) with (fillfactor = 90), + constraint machine_ram_ck_memory_in check ( + [in] between 0 and power(2, 53) - 1 and + [in] between minimum and maximum and + [in] <= total + ) with (fillfactor = 90), + constraint machine_ram_ck_memory_out check ( + [out] between 0 and power(2, 53) - 1 and + [out] between minimum and maximum and + [out] <= total + ) with (fillfactor = 90), + constraint machine_ram_ck_memory_minimum check ( + minimum between 0 and power(2, 53) - 1 and + minimum <= total and + minimum <= maximum + ) with (fillfactor = 90), + constraint machine_ram_ck_memory_maximum check ( + maximum between 0 and power(2, 53) - 1 and + maximum between total and minimum + ) with (fillfactor = 90), + constraint machine_ram_ck_memory_average check ( + average between 0 and power(2, 53) - 1 and + average between minimum and maximum and + average <= total + ) with (fillfactor = 90) + ) + + if object_id(N'dbo.MachineDisks', N'U') is null create table dbo.MachineDisks( + id integer not null identity(1, 1), + machine integer not null, + [disk] integer not null, + belongs bit not null constraint machine_disks_df_belongs default 1, + mounted bit not null constraint machine_disks_df_mounted default 1, + date_in datetime not null constraint machine_disks_df_date_in default getdate(), + date_out datetime, + constraint machine_disks_pk primary key clustered (id), + constraint machine_disks_fk_machine foreign key (machine) references dbo.Machines(id) + on update no action + on delete no action, + constraint machine_disks_fk_disk foreign key ([disk]) references dbo.Disks(id) + on update no action + on delete no action + ) + + if object_id(N'dbo.MachineInterfaces', N'U') is null create table dbo.MachineInterfaces( + id integer not null identity(1, 1), + machine integer not null, + [interface] integer not null, + belongs bit not null constraint machine_interfaces_df_belongs default 1, + mounted bit not null constraint machine_interfaces_df_mounted default 1, + date_in datetime not null constraint machine_interfaces_df_date_in default getdate(), + date_out datetime, + constraint machine_interfaces_pk primary key clustered (id), + constraint machine_interfaces_fk_machine foreign key (machine) references dbo.Machines(id) + on update no action + on delete no action, + constraint machine_interfaces_fk_interface foreign key ([interface]) references dbo.Interfaces(id) + on update no action + on delete no action + ) + + if object_id(N'dbo.Procedures', N'U') is null create table dbo.Procedures( + id integer not null identity(1, 1), + [database] integer not null, + [name] varchar(64) not null, + date_in datetime not null constraint procedures_df_date_in default getdate(), + date_out datetime, + constraint procedures_pk primary key clustered (id), + constraint procedures_fk_database foreign key ([database]) references dbo.Databases(id) + on update no action + on delete no action, + constraint procedures_uk_name unique nonclustered ([database] asc, [name] asc) with (fillfactor = 90), + constraint procedures_ck_name check ([name] like '[a-zA-Z_][a-zA-Z0-9_]{0,63}') with (fillfactor = 90) + ) + + -- Level 2. + if object_id(N'dbo.MachineDisksSpace', N'U') is null create table dbo.MachineDisksSpace( + id integer not null identity(1, 1), + machine_disk integer not null, + candle_time integer not null, + free bigint not null, + date_in datetime not null constraint machine_disks_space_df_date_in default getdate(), + date_out datetime, + constraint machine_disks_space_pk primary key clustered (id), + constraint machine_disks_space_fk_machine_disk foreign key (machine_disk) references dbo.MachineDisks(id) + on update no action + on delete no action, + constraint machine_disks_space_fk_candle_time foreign key (candle_time) references dbo.CandlesTimes(id) + on update no action + on delete no action, + constraint machine_disks_space_ck_free check ( + free between 0 and power(2, 53) - 1 and + free <= isnull(( + select top 1 disks.[size] + from dbo.Disks disks + join dbo.MachineDisks machine_disks on machine_disks.[disk] = disks.id + where + disks.date_out is null and + machine_disks.date_out is null and + machine_disks.belongs = 1 and + machine_disks.id = machine_disk + ), 0) + ) with (fillfactor = 90) + ) + + if object_id(N'dbo.MachineInterfacesTraffic', N'U') is null create table dbo.MachineInterfacesTraffic( + id integer not null identity(1, 1), + machine_interface integer not null, + candle_time integer not null, + bytes bigint not null, + packages integer not null, + errors integer not null, + date_in datetime not null constraint machine_interfaces_traffic_df_date_in default getdate(), + date_out datetime, + constraint machine_interfaces_traffic_pk primary key clustered (id), + constraint machine_interfaces_traffic_fk_machine_interface foreign key (machine_interface) references dbo.MachineInterfaces(id) + on update no action + on delete no action, + constraint machine_interfaces_traffic_fk_candle_time foreign key (candle_time) references dbo.CandlesTimes(id) + on update no action + on delete no action, + constraint machine_interfaces_traffic_ck_bytes check ( + bytes between 0 and power(2, 53) - 1 + ) with (fillfactor = 90), + constraint machine_interfaces_traffic_ck_packages check ( + packages between 0 and power(2, 31) - 1 + ) with (fillfactor = 90), + constraint machine_interfaces_traffic_ck_errors check ( + errors between 0 and power(2, 31) - 1 + ) with (fillfactor = 90) + ) + + if object_id(N'dbo.MachineInterfacesData', N'U') is null create table dbo.MachineInterfacesData( + id integer not null identity(1, 1), + machine_interface integer not null, + is_ipv6 bit not null constraint machine_interfaces_data_df_is_ipv6 default 0, + [address] varchar(45) not null, + mask tinyint not null, + date_in datetime not null constraint machine_interfaces_data_df_date_in default getdate(), + date_out datetime, + constraint machine_interfaces_data_pk primary key clustered (id), + constraint machine_interfaces_data_fk_machine_interface foreign key (machine_interface) references dbo.MachineInterfaces(id) + on update no action + on delete no action, + constraint machine_interfaces_data_ck_is_ipv6 check ( + (is_ipv6 = 0 and [address] like '[0-9]%.%.%.%') or + (is_ipv6 = 1 and [address] like '%:%') + ) with (fillfactor = 90), + constraint machine_interfaces_data_ck_address check ( + ([address] like '[0-9]%.%.%.%' and mask between 0 and 32) or + ([address] like '%:%' and mask between 0 and 128) + ) with (fillfactor = 90), + constraint machine_interfaces_data_ck_mask check ( + (mask between 0 and (case when is_ipv6 = 1 then 128 else 32 end)) + ) with (fillfactor = 90) + ) + + if object_id(N'dbo.Exceptions', N'U') is null create table dbo.Exceptions( + id integer not null identity(1, 1), + [procedure] integer not null, + [message] integer not null, + parameters integer, + exception integer not null, + [status] varchar(16), + code integer, + date_in datetime not null constraint exceptions_df_date_in default getdate(), + date_out datetime, + constraint exceptions_pk primary key clustered (id), + constraint exceptions_fk_procedure foreign key ([procedure]) references dbo.Procedures(id) + on update no action + on delete no action, + constraint exceptions_fk_message foreign key ([message]) references dbo.Messages(id) + on update no action + on delete no action, + constraint exceptions_fk_parameters foreign key (parameters) references dbo.BigData(id) + on update no action + on delete no action, + constraint exceptions_fk_exception foreign key (exception) references dbo.BigData(id) + on update no action + on delete no action + ) + + -- Level Plains. + if object_id(N'dbo.MachineInterfacesPlain', N'U') is null create table dbo.MachineInterfacesPlain( + id integer not null identity(1, 1), + machine integer not null, + interface integer not null, + machine_interface integer not null, + candle_time integer not null, + bytes bigint not null, + packages integer not null, + errors integer not null, + is_ipv6 bit not null constraint machine_interfaces_data_df_is_ipv6 default 0, + [address] varchar(45) not null, + mask tinyint not null, + belongs bit not null constraint machine_interfaces_plain_df_belongs default 1, + date_in datetime not null constraint machine_interfaces_plain_df_date_in default getdate(), + date_out datetime, + constraint machine_interfaces_plain_pk primary key clustered (id), + constraint machine_interfaces_plain_fk_machine foreign key (machine) references dbo.Machines(id) + on update no action + on delete no action, + constraint machine_interfaces_plain_uk_machine_interface unique nonclustered (machine asc, [interface] asc) with (fillfactor = 90), + constraint machine_interfaces_plain_ck_interface check ([interface] like '[a-zA-Z0-9_-]{1,32}') with (fillfactor = 90) + ) + +end +go + +if object_id(N'dbo.tables_update', N'P') is not null drop procedure dbo.tables_update +go +create procedure dbo.tables_update as begin + + set nocount on + +end +go + +if object_id(N'dbo.tables_fill', N'P') is not null drop procedure dbo.tables_fill +go +create procedure dbo.tables_fill as begin + + set nocount on + +end +go + +execute dbo.tables_drop +go +execute dbo.tables_create +go +execute dbo.tables_update +go +execute dbo.tables_fill +go + +if object_id(N'dbo.hash_big_data', N'FN') is not null drop function dbo.hash_big_data +go +create function dbo.hash_big_data (@value varchar(max)) returns binary(64) as begin + return select top 1 convert(binary(64), hashbytes('SHA2_256', convert(nvarchar(max), @value))) +end +go + +if object_id(N'dbo.get_procedure', N'P') is not null drop procedure dbo.get_procedure +go +create procedure dbo.get_procedure + @database varchar(64), + @procedure varchar(64), + @id integer output +as begin + + declare @database_id integer = ( + select top 1 id from dbo.Databases where + date_out is null and + [name] = @database + ) + + set nocount on + + if @database_id is null begin + insert into dbo.Databases([name]) values (@database) + set @database_id = scope_identity() + end + + set @id = ( + select top 1 id from dbo.Procedures where + date_out is null and + [database] = @database_id and + [name] = @procedure + ) + + if @id is null begin + insert into dbo.Procedures([database], [name]) values (@database_id, @procedure) + set @id = scope_identity() + end + +end +go + +if object_id(N'dbo.get_big_data', N'P') is not null drop procedure dbo.get_big_data +go +create procedure dbo.get_big_data + @value varchar(max), + @id integer output +as begin + + declare @hash binary(64) = dbo.hash_big_data(@value) + + set nocount on + + set @id = ( + select top 1 id from dbo.BigData where + date_out is null and + [hash] = @hash + ) + + if @id is null begin + insert into dbo.BigData([hash], [value]) values (@hash, @value) + set @id = scope_identity() + end + +end +go + +if object_id(N'dbo.get_message', N'P') is not null drop procedure dbo.get_message +go +create procedure dbo.get_message + @message varchar(128), + @id integer output +as begin + + set nocount on + + set @id = ( + select top 1 id from dbo.Messages where + date_out is null and + [key] = @message + ) + + if @id is null begin + insert into dbo.Messages([key]) values (@message) + set @id = scope_identity() + end + +end +go + +if object_id(N'dbo.set_exception', N'P') is not null drop procedure dbo.set_exception +go +create procedure dbo.set_exception + @database varchar(64), + @procedure varchar(64), + @message varchar(128), + @parameters varchar(max) = null +as begin + + declare @procedure_id integer + declare @message_id integer + declare @exception_message varchar(max) = error_message() + declare @exception_message_id integer + declare @parameters_id integer + + set nocount on + + execute dbo.get_procedure @database, @procedure, @procedure_id output + execute dbo.get_big_data @exception_message, @exception_message_id output + execute dbo.get_big_data @parameters, @parameters_id output + execute dbo.get_message @message, @message_id output + + insert into dbo.Exceptions([procedure], [message], [parameters], exception, [status], code) values + (@procedure_id, @message_id, @parameters_id, @exception_message_id, error_severity(), error_number()) + +end +go + +if object_id(N'dbo.ProceduresView', N'V') is not null drop view dbo.ProceduresView +go +create view dbo.ProceduresView as select + procedures.id, + databases.[name] as [database], + procedures.[name] as [procedure], + procedures.date_in, + procedures.date_out +from dbo.Procedures procedures +join dbo.Databases databases on databases.id = procedures.[database] +where + procedures.date_out is null and + databases.date_out is null +go + +if object_id(N'dbo.ExceptionsView', N'V') is not null drop view dbo.ExceptionsView +go +create view dbo.ExceptionsView as select + exceptions.id, + procedures.[database] as [database], + procedures.[procedure] as [procedure], + messages.[key] as [message], + parameters.[value] as [parameters], + exception.[value] as [exception], + exceptions.[status], + exceptions.code, + exceptions.date_in +from dbo.Exceptions exceptions +join dbo.ProceduresView procedures on procedures.id = exceptions.[procedure] +join dbo.Messages messages on messages.id = exceptions.[message] +join dbo.BigData parameters on parameters.id = exceptions.parameters +join dbo.BigData exception on exception.id = exceptions.exception +where + exceptions.date_out is null and + procedures.date_out is null and + messages.date_out is null and + parameters.date_out is null and + exception.date_out is null +go \ No newline at end of file diff --git a/version b/version new file mode 100644 index 0000000..8acdd82 --- /dev/null +++ b/version @@ -0,0 +1 @@ +0.0.1