#wip: AI client working.
This commit is contained in:
parent
f1371e7389
commit
c73884ef35
@ -68,7 +68,7 @@
|
|||||||
"AnP_RoutesManager_end" : null,
|
"AnP_RoutesManager_end" : null,
|
||||||
|
|
||||||
"AnP_WebSocketsServersManager_start" : null,
|
"AnP_WebSocketsServersManager_start" : null,
|
||||||
"default_web_sockets_servers2" : {
|
"default_web_sockets_servers" : {
|
||||||
"anp" : {
|
"anp" : {
|
||||||
"type" : "WebSocketServerDriver",
|
"type" : "WebSocketServerDriver",
|
||||||
"host" : "",
|
"host" : "",
|
||||||
|
|||||||
@ -31,10 +31,10 @@
|
|||||||
"AnP_RoutesManager_end" : null,
|
"AnP_RoutesManager_end" : null,
|
||||||
|
|
||||||
"AnP_WebSocketServerDriver_start" : null,
|
"AnP_WebSocketServerDriver_start" : null,
|
||||||
"web_socket_server_client_close_exception" : "El Web Socket Servidor '{host}:{port}' ha cerrado la conexión con el cliente '{key}'.",
|
"web_socket_server_client_close_exception" : "El Web Socket Servidor '{host}:{port}' ha cerrado la conexión con el cliente '{id}'.",
|
||||||
"web_socket_server_client_connected" : "El cliente '{key}' se ha conectado al Web Socket Servidor '{host}:{port}' desde '{client_host}:{client_port}'.",
|
"web_socket_server_client_connected" : "El cliente '{id}' se ha conectado al Web Socket Servidor '{host}:{port}' desde '{client_host}:{client_port}'.",
|
||||||
"web_socket_server_client_exception" : "Excepción al intentar procesar un mensaje de recepción del cliente '{key}' en el Web Socket Servidor '{host}:{port}'.",
|
"web_socket_server_client_exception" : "Excepción al intentar procesar un mensaje de recepción del cliente '{id}' en el Web Socket Servidor '{host}:{port}'.",
|
||||||
"web_socket_server_client_disconnected" : "El cliente '{key}' se ha desconectado del Web Socket Servidor '{host}:{port}'.",
|
"web_socket_server_client_disconnected" : "El cliente '{id}' se ha desconectado del Web Socket Servidor '{host}:{port}'.",
|
||||||
"AnP_WebSocketServerDriver_end" : null,
|
"AnP_WebSocketServerDriver_end" : null,
|
||||||
|
|
||||||
"AnP_TitlesManager_start" : null,
|
"AnP_TitlesManager_start" : null,
|
||||||
|
|||||||
146
Public/ecma/Abstracts/WebSocketsClientsAbstract.ecma.js
Normal file
146
Public/ecma/Abstracts/WebSocketsClientsAbstract.ecma.js
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import {Event} from "../Application/Event.ecma.js";
|
||||||
|
import {Check} from "../Utils/Checks.ecma.js";
|
||||||
|
import {Common} from "../Utils/Common.ecma.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class WebSocketsClientsAbstract
|
||||||
|
* @constructor
|
||||||
|
* @param {!AnP} anp
|
||||||
|
* @param {!string} key
|
||||||
|
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||||
|
* @return {void}
|
||||||
|
* @access public
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
export const WebSocketsClientsAbstract = (function(){
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructs WebSocketsClientsAbstract
|
||||||
|
* @param {!AnP} anp
|
||||||
|
* @param {!string} key
|
||||||
|
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||||
|
* @return {void}
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
const WebSocketsClientsAbstract = function(anp, key, inputs){
|
||||||
|
|
||||||
|
/** @type {WebSocketsClientsAbstract|Object.<string, any|null>} */
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
/** @type {string|null} */
|
||||||
|
this.key = null;
|
||||||
|
/** @type {string|null} */
|
||||||
|
this.url = null;
|
||||||
|
/** @type {string|null} */
|
||||||
|
this.id = null;
|
||||||
|
/** @type {Event} */
|
||||||
|
this.on_open = new Event();
|
||||||
|
/** @type {Event} */
|
||||||
|
this.on_message = new Event();
|
||||||
|
/** @type {Event} */
|
||||||
|
this.on_close = new Event();
|
||||||
|
/** @type {Event} */
|
||||||
|
this.on_error = new Event();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Object.<string, any|null>} item
|
||||||
|
* @returns {void}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.change_self = item => {
|
||||||
|
self = item;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const constructor = () => {
|
||||||
|
|
||||||
|
self.key = key;
|
||||||
|
self.url = Common.get_value("url", (
|
||||||
|
Check.is_string(inputs) ? inputs = {url : inputs} :
|
||||||
|
inputs), "");
|
||||||
|
|
||||||
|
self.on_open.add(on_opened);
|
||||||
|
self.on_message.add(on_received);
|
||||||
|
self.on_close.add(on_closed);
|
||||||
|
self.on_error.add(on_errored);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const on_opened = () => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} inputs
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const on_received = inputs => {
|
||||||
|
|
||||||
|
/** @type {Object.<string, any|null>} */
|
||||||
|
const data = Common.data_decode(inputs);
|
||||||
|
|
||||||
|
switch(data.controller + "." + data.action){
|
||||||
|
case "web_socket_client.set_id":
|
||||||
|
self.id = data.data;
|
||||||
|
console.log(self.id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
anp.controllers.execute(data.controller, data.action, data, data.code);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} controller
|
||||||
|
* @param {!string} action
|
||||||
|
* @param {?any} [data = null]
|
||||||
|
* @param {!number} [code = 200]
|
||||||
|
* @return {void}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.send = (controller, action, data, code = 200) => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {void}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.close = () => {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const on_closed = () => {
|
||||||
|
self.id = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} error
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const on_errored = error => {
|
||||||
|
console.error(error);
|
||||||
|
self.close();
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return WebSocketsClientsAbstract;
|
||||||
|
})();
|
||||||
@ -8,6 +8,7 @@ import {ThreadsManager} from "../Managers/ThreadsManager.ecma.js";
|
|||||||
import {UniqueKeysManager} from "../Managers/UniqueKeysManager.ecma.js";
|
import {UniqueKeysManager} from "../Managers/UniqueKeysManager.ecma.js";
|
||||||
import {SessionsManager} from "../Managers/SessionsManager.ecma.js";
|
import {SessionsManager} from "../Managers/SessionsManager.ecma.js";
|
||||||
import {ModelsManager} from "../Managers/ModelsManager.ecma.js";
|
import {ModelsManager} from "../Managers/ModelsManager.ecma.js";
|
||||||
|
import {ControllersManager} from "../Managers/ControllersManager.ecma.js";
|
||||||
import {ViewsManager} from "../Managers/ViewsManager.ecma.js";
|
import {ViewsManager} from "../Managers/ViewsManager.ecma.js";
|
||||||
import {RoutesManager} from "../Managers/RoutesManager.ecma.js";
|
import {RoutesManager} from "../Managers/RoutesManager.ecma.js";
|
||||||
import {WebSocketsClientsManager} from "../Managers/WebSocketsClientsManager.ecma.js";
|
import {WebSocketsClientsManager} from "../Managers/WebSocketsClientsManager.ecma.js";
|
||||||
@ -70,6 +71,8 @@ export const AnP = (function(){
|
|||||||
this.models = new ModelsManager(self);
|
this.models = new ModelsManager(self);
|
||||||
/** @type {Components} */
|
/** @type {Components} */
|
||||||
this.components = new Components(self);
|
this.components = new Components(self);
|
||||||
|
/** @type {ControllersManager} */
|
||||||
|
this.controllers = new ControllersManager(self);
|
||||||
/** @type {ViewsManager} */
|
/** @type {ViewsManager} */
|
||||||
this.views = new ViewsManager(self);
|
this.views = new ViewsManager(self);
|
||||||
/** @type {RoutesManager} */
|
/** @type {RoutesManager} */
|
||||||
@ -94,7 +97,7 @@ export const AnP = (function(){
|
|||||||
*/
|
*/
|
||||||
this.update = (callback = null) => {
|
this.update = (callback = null) => {
|
||||||
Common.execute_array([
|
Common.execute_array([
|
||||||
"files", "settings", "print_types", "i18n", "threads", "models", "views", "routes"
|
"files", "settings", "print_types", "i18n", "threads", "models", "controllers", "views", "routes", "web_sockets_clients"
|
||||||
], (key, next) => {
|
], (key, next) => {
|
||||||
self[key].update(next);
|
self[key].update(next);
|
||||||
}, callback, true);
|
}, callback, true);
|
||||||
@ -107,7 +110,7 @@ export const AnP = (function(){
|
|||||||
*/
|
*/
|
||||||
this.reset = (callback = null) => {
|
this.reset = (callback = null) => {
|
||||||
Common.execute_array([
|
Common.execute_array([
|
||||||
"files", "settings", "print_types", "i18n", "threads", "models", "views", "routes"
|
"files", "settings", "print_types", "i18n", "threads", "models", "controllers", "views", "routes", "web_sockets_clients"
|
||||||
], (key, next) => {
|
], (key, next) => {
|
||||||
self[key].reset(next);
|
self[key].reset(next);
|
||||||
}, callback, true);
|
}, callback, true);
|
||||||
@ -161,7 +164,11 @@ export const AnP = (function(){
|
|||||||
};
|
};
|
||||||
started = false;
|
started = false;
|
||||||
|
|
||||||
end(true);
|
Common.execute_array(["web_sockets_clients"], (key, next) => {
|
||||||
|
self[key].close(next);
|
||||||
|
}, () => {
|
||||||
|
end(true);
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -47,6 +47,8 @@ export const Components = (function(){
|
|||||||
|
|
||||||
/** @type {Components} */
|
/** @type {Components} */
|
||||||
const self = this;
|
const self = this;
|
||||||
|
/** @type {number|null} */
|
||||||
|
let thread = null;
|
||||||
|
|
||||||
/** @type {BaseComponent} */
|
/** @type {BaseComponent} */
|
||||||
this.base = new BaseComponent(anp);
|
this.base = new BaseComponent(anp);
|
||||||
@ -71,7 +73,32 @@ export const Components = (function(){
|
|||||||
* @returns {void}
|
* @returns {void}
|
||||||
* @access private
|
* @access private
|
||||||
*/
|
*/
|
||||||
const constructor = () => {};
|
const constructor = () => {
|
||||||
|
|
||||||
|
thread = anp.threads.add(thread_method, {
|
||||||
|
autostart : true,
|
||||||
|
bucle : true,
|
||||||
|
timer : 100
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const thread_method = () => {
|
||||||
|
document.querySelectorAll(".anp .input .field-information[data-i18n=length]").forEach(item => {
|
||||||
|
|
||||||
|
/** @type {HTMLSpanElement} */
|
||||||
|
const field = item.querySelector(".value"),
|
||||||
|
/** @type {HTMLInputElement|HTMLTextAreaElement} */
|
||||||
|
input = item.parentNode.parentNode.querySelector("input,textarea");
|
||||||
|
|
||||||
|
field.textContent != input.value.length && (field.textContent = input.value.length);
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {!(string|Array.<string>)} keys
|
* @param {!(string|Array.<string>)} keys
|
||||||
@ -117,6 +144,7 @@ export const Components = (function(){
|
|||||||
},
|
},
|
||||||
on_error : (item, event) => {
|
on_error : (item, event) => {
|
||||||
|
|
||||||
|
/** @type {number} */
|
||||||
const i = Number(item.parentNode.getAttribute("data_i")) + 1;
|
const i = Number(item.parentNode.getAttribute("data_i")) + 1;
|
||||||
|
|
||||||
item.setAttribute("src", Common.json_decode(Common.base64_decode(item.parentNode.getAttribute("data-data")))[i]);
|
item.setAttribute("src", Common.json_decode(Common.base64_decode(item.parentNode.getAttribute("data-data")))[i]);
|
||||||
@ -129,21 +157,45 @@ export const Components = (function(){
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} i18n
|
||||||
|
* @param {!string} [tag = "span"]
|
||||||
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [variables = null]
|
||||||
|
* @returns {Array.<any|null>}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
this.i18n = (i18n, tag = "span", variables = null) => [tag, {
|
this.i18n = (i18n, tag = "span", variables = null) => [tag, {
|
||||||
data_i18n : i18n,
|
data_i18n : i18n,
|
||||||
...(variables ? {data_i18n_variables : Common.data_encode(variables)} : {})
|
...(variables ? {data_i18n_variables : Common.data_encode(variables)} : {})
|
||||||
}, anp.i18n.get(i18n, variables)];
|
}, anp.i18n.get(i18n, variables)];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} icon
|
||||||
|
* @param {!string} [tag = "span"]
|
||||||
|
* @returns {Array.<any|null>}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
this.icon = (icon, tag = "span") => [tag, {data_icon : icon}];
|
this.icon = (icon, tag = "span") => [tag, {data_icon : icon}];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} name
|
||||||
|
* @param {!(string|event_callback)} action
|
||||||
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||||
|
* @returns {Array.<any|null>}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
this.button = (name, action, inputs = null) => {
|
this.button = (name, action, inputs = null) => {
|
||||||
|
|
||||||
|
/** @type {string} */
|
||||||
const text = anp.i18n.get(name, (
|
const text = anp.i18n.get(name, (
|
||||||
Check.is_bool(inputs) ? {toogled : inputs} :
|
Check.is_bool(inputs) ? {toogled : inputs} :
|
||||||
Check.is_string(inputs) ? {type : inputs} :
|
Check.is_string(inputs) ? {type : inputs} :
|
||||||
inputs)),
|
inputs)),
|
||||||
|
/** @type {boolean} */
|
||||||
has_action = Check.is_function(action),
|
has_action = Check.is_function(action),
|
||||||
|
/** @type {string} */
|
||||||
type = Check.is_string(action) ? action : Common.get_value("type", inputs, "button"),
|
type = Check.is_string(action) ? action : Common.get_value("type", inputs, "button"),
|
||||||
|
/** @type {boolean|null} */
|
||||||
toggled = Common.get_value("toggled", inputs, null);
|
toggled = Common.get_value("toggled", inputs, null);
|
||||||
|
|
||||||
has_action || (action = null);
|
has_action || (action = null);
|
||||||
@ -169,6 +221,12 @@ export const Components = (function(){
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} name
|
||||||
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||||
|
* @returns {Array.<any|null>}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
this.checkbox = (name, inputs = null) => Label({
|
this.checkbox = (name, inputs = null) => Label({
|
||||||
class : "checkbox",
|
class : "checkbox",
|
||||||
data_i18n : name,
|
data_i18n : name,
|
||||||
@ -188,8 +246,15 @@ export const Components = (function(){
|
|||||||
self.i18n(name)
|
self.i18n(name)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} name
|
||||||
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||||
|
* @returns {Array.<any|null>}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
this.radio = (name, inputs = null) => {
|
this.radio = (name, inputs = null) => {
|
||||||
|
|
||||||
|
/** @type {string|null} */
|
||||||
const set = Common.get_value("set", inputs);
|
const set = Common.get_value("set", inputs);
|
||||||
|
|
||||||
return Label({
|
return Label({
|
||||||
@ -213,10 +278,36 @@ export const Components = (function(){
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} name
|
||||||
|
* @param {?any} value
|
||||||
|
* @returns {Array.<any|null>}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
const field_information = (name, value) => Span({
|
||||||
|
class : "field-information",
|
||||||
|
data_i18n : name,
|
||||||
|
data_i18n_without : true,
|
||||||
|
title : anp.i18n.get(name),
|
||||||
|
data_value : "" + value
|
||||||
|
}, [
|
||||||
|
self.i18n(name),
|
||||||
|
Span({class : "value"}, "" + value)
|
||||||
|
]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} name
|
||||||
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||||
|
* @returns {Array.<any|null>}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
this.text = (name, inputs = null) => {
|
this.text = (name, inputs = null) => {
|
||||||
|
|
||||||
|
/** @type {string} */
|
||||||
const text = anp.i18n.get(name),
|
const text = anp.i18n.get(name),
|
||||||
|
/** @type {number|null} */
|
||||||
minimum_length = Common.get_value("minimum_length", inputs, null),
|
minimum_length = Common.get_value("minimum_length", inputs, null),
|
||||||
|
/** @type {number|null} */
|
||||||
maximum_length = Common.get_value("maximum_length", inputs, null);
|
maximum_length = Common.get_value("maximum_length", inputs, null);
|
||||||
|
|
||||||
return Span({
|
return Span({
|
||||||
@ -249,17 +340,28 @@ export const Components = (function(){
|
|||||||
"value"
|
"value"
|
||||||
], inputs)
|
], inputs)
|
||||||
}),
|
}),
|
||||||
Span({class : "minimum", data_minimum : minimum_length}, "" + minimum_length),
|
Span({class : "information"}, [
|
||||||
Span({class : "length"}, "" + Common.get_value("value", inputs, "").length),
|
field_information("minimum", minimum_length),
|
||||||
Span({class : "maximum", data_maximum : maximum_length}, "" + maximum_length)
|
field_information("length", Common.get_value("value", inputs, "").length),
|
||||||
|
field_information("maximum", maximum_length),
|
||||||
|
])
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} name
|
||||||
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||||
|
* @returns {Array.<any|null>}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
this.password = (name, inputs = null) => {
|
this.password = (name, inputs = null) => {
|
||||||
|
|
||||||
|
/** @type {string} */
|
||||||
const text = anp.i18n.get(name),
|
const text = anp.i18n.get(name),
|
||||||
minimum_length = Common.get_value("minimum_length", inputs, 0),
|
/** @type {number|null} */
|
||||||
maximum_length = Common.get_value("maximum_length", inputs, 0);
|
minimum_length = Common.get_value("minimum_length", inputs, null),
|
||||||
|
/** @type {number|null} */
|
||||||
|
maximum_length = Common.get_value("maximum_length", inputs, null);
|
||||||
|
|
||||||
return Span({
|
return Span({
|
||||||
data_i18n : name,
|
data_i18n : name,
|
||||||
@ -279,14 +381,23 @@ export const Components = (function(){
|
|||||||
"value"
|
"value"
|
||||||
], inputs)
|
], inputs)
|
||||||
}),
|
}),
|
||||||
Span({class : "minimum", data_minimum : minimum_length}, "" + minimum_length),
|
Span({class : "information"}, [
|
||||||
Span({class : "length"}, "" + Common.get_value("value", inputs, "").length),
|
field_information("minimum", minimum_length),
|
||||||
Span({class : "maximum", data_maximum : maximum_length}, "" + maximum_length)
|
field_information("length", Common.get_value("value", inputs, "").length),
|
||||||
|
field_information("maximum", maximum_length),
|
||||||
|
])
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} name
|
||||||
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||||
|
* @returns {Array.<any|null>}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
this.email = (name, inputs = null) => {
|
this.email = (name, inputs = null) => {
|
||||||
|
|
||||||
|
/** @type {string} */
|
||||||
const text = anp.i18n.get(name);
|
const text = anp.i18n.get(name);
|
||||||
|
|
||||||
return Span({
|
return Span({
|
||||||
@ -305,12 +416,22 @@ export const Components = (function(){
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} name
|
||||||
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||||
|
* @returns {Array.<any|null>}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
this.number = (name, inputs = null) => {
|
this.number = (name, inputs = null) => {
|
||||||
|
|
||||||
|
/** @type {string} */
|
||||||
const text = anp.i18n.get(name),
|
const text = anp.i18n.get(name),
|
||||||
minimum = Common.get_value("minimum", inputs, 0),
|
/** @type {number|null} */
|
||||||
maximum = Common.get_value("maximum", inputs, 0),
|
minimum = Common.get_value("minimum", inputs, null),
|
||||||
value = Common.get_value("value", inputs, 0);
|
/** @type {number|null} */
|
||||||
|
maximum = Common.get_value("maximum", inputs, null),
|
||||||
|
/** @type {number|null} */
|
||||||
|
value = Common.get_value("value", inputs, null);
|
||||||
|
|
||||||
return Span({
|
return Span({
|
||||||
data_i18n : name,
|
data_i18n : name,
|
||||||
@ -331,9 +452,11 @@ export const Components = (function(){
|
|||||||
"value"
|
"value"
|
||||||
], inputs)
|
], inputs)
|
||||||
}),
|
}),
|
||||||
Span({class : "minimum", data_minimum : minimum}, "" + minimum),
|
Span({class : "information"}, [
|
||||||
Span({class : "value"}, "" + value),
|
field_information("minimum", minimum),
|
||||||
Span({class : "maximum", data_maximum : maximum}, "" + maximum)
|
// field_information("value", value),
|
||||||
|
field_information("maximum", maximum),
|
||||||
|
])
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -341,6 +464,7 @@ export const Components = (function(){
|
|||||||
* @param {!Array.<Array.<[string, string|event_callback, Object.<string, any|null>|Array.<any|null>]>>} buttons
|
* @param {!Array.<Array.<[string, string|event_callback, Object.<string, any|null>|Array.<any|null>]>>} buttons
|
||||||
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
|
||||||
* @returns {Array.<any|null>}
|
* @returns {Array.<any|null>}
|
||||||
|
* @access public
|
||||||
*/
|
*/
|
||||||
this.buttons = (buttons, inputs = null) => Div({
|
this.buttons = (buttons, inputs = null) => Div({
|
||||||
class : ["buttons"].concat(Common.get_array(Common.get_value("class", inputs, []))).join(" ").trim(),
|
class : ["buttons"].concat(Common.get_array(Common.get_value("class", inputs, []))).join(" ").trim(),
|
||||||
|
|||||||
@ -33,9 +33,9 @@ export const Event = (function(){
|
|||||||
/** @type {Event} */
|
/** @type {Event} */
|
||||||
const self = this,
|
const self = this,
|
||||||
/** @type {Object.<number, event_callback>} */
|
/** @type {Object.<number, event_callback>} */
|
||||||
events = {},
|
events = {};
|
||||||
/** @type {number} */
|
/** @type {number} */
|
||||||
id_i = 0;
|
let id_i = 0;
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
this.once = once;
|
this.once = once;
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import {Fieldset, Section, Form, Div} from "../Utils/HTMLDSL.ecma.js";
|
import {
|
||||||
|
Fieldset, Section, Form, Div, Nav, UL, LI, Span, Pre
|
||||||
|
} from "../Utils/HTMLDSL.ecma.js";
|
||||||
|
import {MarkDown} from "../Utils/MarkDown.ecma.js";
|
||||||
import {Common} from "../Utils/Common.ecma.js";
|
import {Common} from "../Utils/Common.ecma.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,8 +44,6 @@ export const AIChatComponent = (function(){
|
|||||||
|
|
||||||
const name = Common.get_value("name", inputs, "aichat");
|
const name = Common.get_value("name", inputs, "aichat");
|
||||||
|
|
||||||
web_socket_id = anp.web_sockets_clients.add("AAA", "https://localhost:18000/");
|
|
||||||
|
|
||||||
return Fieldset({class : "aichat"}, [
|
return Fieldset({class : "aichat"}, [
|
||||||
anp.components.i18n(name, "legend"),
|
anp.components.i18n(name, "legend"),
|
||||||
Section({class : "messages"}),
|
Section({class : "messages"}),
|
||||||
@ -60,6 +61,86 @@ export const AIChatComponent = (function(){
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const build_data_icon = (name, value) => LI({
|
||||||
|
data_name : name,
|
||||||
|
data_i18n : value,
|
||||||
|
data_i18n_without : true,
|
||||||
|
title : anp.components.i18n(value)
|
||||||
|
}, [
|
||||||
|
anp.components.icon(value),
|
||||||
|
anp.components.i18n(value)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const build_data_item = (name, value = null) => LI({
|
||||||
|
data_name : name,
|
||||||
|
data_i18n : name,
|
||||||
|
data_i18n_without : true,
|
||||||
|
title : anp.components.i18n(name)
|
||||||
|
}, [
|
||||||
|
anp.components.icon(name),
|
||||||
|
anp.components.i18n(name),
|
||||||
|
value === null ? null : Span({class : "value"}, "" + value)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const get_message_box = item => {
|
||||||
|
|
||||||
|
while((!item.classList || !item.classList.contains("message")) && (item = item.parentElement));
|
||||||
|
|
||||||
|
return item;
|
||||||
|
};
|
||||||
|
|
||||||
|
const set_view = (item, event) => {
|
||||||
|
|
||||||
|
const box = get_message_box(item),
|
||||||
|
mode = item.getAttribute("data-i18n");
|
||||||
|
|
||||||
|
box.getAttribute("data-mode") != mode && box.setAttribute("data-mode", mode);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const format = content => {
|
||||||
|
|
||||||
|
const html = MarkDown.to_html(content);
|
||||||
|
|
||||||
|
return [html, html.replace(/</g, "<").replace(/>/g, ">"), content];
|
||||||
|
};
|
||||||
|
|
||||||
|
const build_message = (id, type, content = "", mode = "waiting") => {
|
||||||
|
|
||||||
|
const [html, raw_html, md] = format(content),
|
||||||
|
date = Date.now();
|
||||||
|
|
||||||
|
return Fieldset({
|
||||||
|
class : "message",
|
||||||
|
data_id : id,
|
||||||
|
data_type : type,
|
||||||
|
data_ok : true,
|
||||||
|
data_status : mode,
|
||||||
|
data_done : mode == "done",
|
||||||
|
data_mode : "html"
|
||||||
|
}, [
|
||||||
|
anp.components.i18n(type, "legend"),
|
||||||
|
Div({class : "message-box html-content"}, html),
|
||||||
|
Pre({class : "message-box raw-html-content"}, raw_html),
|
||||||
|
Pre({class : "message-box md-content"}, md),
|
||||||
|
Nav({class : "view buttons"}, [
|
||||||
|
anp.components.button("html", set_view),
|
||||||
|
anp.components.button("raw_html", set_view),
|
||||||
|
anp.components.button("md", set_view),
|
||||||
|
]),
|
||||||
|
UL({class : "data"}, [
|
||||||
|
build_data_icon("status", mode),
|
||||||
|
build_data_item("ok"),
|
||||||
|
build_data_item("done"),
|
||||||
|
build_data_item("date_from", date),
|
||||||
|
build_data_item("date_to", date),
|
||||||
|
build_data_item("time", 0),
|
||||||
|
build_data_item("length", content.length),
|
||||||
|
build_data_item("response_tokens", content.replace(/(?:[^a-z0-9]+|[\r\n]+)+/gi, " ").trim().split(" ").length)
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
const send = (item, event) => {
|
const send = (item, event) => {
|
||||||
|
|
||||||
const text_box = item.querySelector("[name=message]"),
|
const text_box = item.querySelector("[name=message]"),
|
||||||
@ -68,15 +149,21 @@ export const AIChatComponent = (function(){
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
if(text){
|
if(text){
|
||||||
Common.HTML(".aichat .messages", Fieldset({
|
|
||||||
class : "message",
|
const data_id = anp.unique_keys.get();
|
||||||
data_type : "user",
|
|
||||||
data_id : anp.unique_keys.create()
|
Common.HTML(
|
||||||
}, [
|
".aichat .messages",
|
||||||
anp.components.i18n("user", "legend"),
|
build_message(data_id, "user", text, "done"),
|
||||||
Div({class : "content"}, text)
|
build_message(data_id, "bot")
|
||||||
]));
|
);
|
||||||
text_box.value = "";
|
text_box.value = "";
|
||||||
|
|
||||||
|
anp.web_sockets_clients.send("anp", "ai", "message", {
|
||||||
|
message_id : data_id,
|
||||||
|
message : text
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -86,24 +173,35 @@ export const AIChatComponent = (function(){
|
|||||||
event.key == "Enter" && !event.shiftKey && send(item, event);
|
event.key == "Enter" && !event.shiftKey && send(item, event);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.write_response = (id, fragment) => {
|
this.write_response = (id, fragment, ok, done) => {
|
||||||
|
|
||||||
let box = document.querySelector(".aichat .messages>[data-type=bot][data-id='" + id + "']");
|
const box = document.querySelector(".aichat .messages>[data-type=bot][data-id='" + id + "']"),
|
||||||
|
status = (
|
||||||
|
!ok ? "error" :
|
||||||
|
done ? "done" :
|
||||||
|
"loading"),
|
||||||
|
status_text = anp.i18n.get(status),
|
||||||
|
status_box = box.querySelector("[data-name=status]"),
|
||||||
|
status_i18n_box = status_box.querySelector("[data-i18n]"),
|
||||||
|
date = Date.now(),
|
||||||
|
tokens_box = box.querySelector("[data-name=response_tokens] .value"),
|
||||||
|
[html, raw_html, md] = format(box.querySelector(".md-content").innerText += fragment);
|
||||||
|
|
||||||
if(!box){
|
box.querySelector(".html-content").innerHTML = html;
|
||||||
if(!document.querySelector(".aichat .messages>[data-type=user][data-id='" + id + "']"))
|
box.querySelector(".raw-html-content").innerHTML = raw_html;
|
||||||
return;
|
|
||||||
box = Common.HTML(".aichat .messages", Fieldset({
|
|
||||||
class : "message",
|
|
||||||
data_type : "box",
|
|
||||||
data_id : id
|
|
||||||
}, [
|
|
||||||
anp.components.i18n("assistant", "legend"),
|
|
||||||
Div({class : "content"}, "")
|
|
||||||
]), true)[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
box.querySelector(".content").innerHTML += fragment;
|
box.setAttribute("data-ok", ok);
|
||||||
|
box.setAttribute("data-done", done);
|
||||||
|
box.setAttribute("data-status", status);
|
||||||
|
|
||||||
|
status_box.setAttribute("data-i18n", status);
|
||||||
|
status_box.setAttribute("title", status_text);
|
||||||
|
status_i18n_box.setAttribute("data-i18n", status_text);
|
||||||
|
status_i18n_box.innerHTML = status_text;
|
||||||
|
|
||||||
|
box.querySelector("[data-name=date_to]").querySelector(".value").innerHTML = date;
|
||||||
|
box.querySelector("[data-name=time]").querySelector(".value").innerHTML = date - Number(box.querySelector("[data-name=date_from] .value").innerText);
|
||||||
|
tokens_box.innerText = Number(tokens_box.innerText) + 1;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -123,7 +123,7 @@ export const BaseComponent = (function(){
|
|||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
logo = anp.settings.get(["application_logo", "logo"], inputs, "images/logo.webp"),
|
logo = anp.settings.get(["application_logo", "logo"], inputs, "images/logo.webp"),
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
id = anp.unique_keys.create(),
|
id = anp.unique_keys.get(),
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
gui_mode = Check.is_dark_mode() ? "dark" : "light",
|
gui_mode = Check.is_dark_mode() ? "dark" : "light",
|
||||||
/** @type {boolean} */
|
/** @type {boolean} */
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class AIChat
|
|
||||||
* @constructor
|
|
||||||
* @param {!AnP} anp
|
|
||||||
* @returns {void}
|
|
||||||
* @access private
|
|
||||||
* @static
|
|
||||||
*/
|
|
||||||
export const AIChat = (function(){
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constructs AIChat
|
|
||||||
* @param {!AnP} anp
|
|
||||||
* @returns {void}
|
|
||||||
* @access private
|
|
||||||
* @static
|
|
||||||
*/
|
|
||||||
const AIChat = function(anp){
|
|
||||||
|
|
||||||
/** @type {AIChat} */
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {void}
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
const constructor = () => {};
|
|
||||||
|
|
||||||
constructor();
|
|
||||||
};
|
|
||||||
|
|
||||||
return AIChat;
|
|
||||||
})();
|
|
||||||
55
Public/ecma/Controllers/AIController.ecma.js
Normal file
55
Public/ecma/Controllers/AIController.ecma.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class AIController
|
||||||
|
* @constructor
|
||||||
|
* @param {!AnP} anp
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
export const AIController = (function(){
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructs AIController
|
||||||
|
* @param {!AnP} anp
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
const AIController = function(anp){
|
||||||
|
|
||||||
|
/** @type {AIChat} */
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const constructor = () => {};
|
||||||
|
|
||||||
|
this.test = (...parameters) => {
|
||||||
|
console.log(parameters);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.message = (data, code) => {
|
||||||
|
|
||||||
|
anp.components.aichat.write_response(data.data.data_id, data.data.response, data.data.ok, data.data.done);
|
||||||
|
|
||||||
|
// const box = document.querySelector(".aichat .messages [data-type=bot][data-id=" + data.data.data_id + "]");
|
||||||
|
|
||||||
|
// box.querySelector(".content").innerHTML += data.data.response;
|
||||||
|
// box.setAttribute("data-done", data.data.done);
|
||||||
|
// box.setAttribute("data-ok", data.data.ok);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor();
|
||||||
|
};
|
||||||
|
|
||||||
|
return AIController;
|
||||||
|
})();
|
||||||
@ -196,6 +196,7 @@ export const FilesDriver = (function(){
|
|||||||
date = Date.now();
|
date = Date.now();
|
||||||
|
|
||||||
ajax.open(method, root_urls[i] + url, asynchronous);
|
ajax.open(method, root_urls[i] + url, asynchronous);
|
||||||
|
ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
|
||||||
ajax.timeout = timeout;
|
ajax.timeout = timeout;
|
||||||
ajax.onreadystatechange = () => {
|
ajax.onreadystatechange = () => {
|
||||||
if(ended)
|
if(ended)
|
||||||
|
|||||||
173
Public/ecma/Drivers/WebSocketsClientsDriver.ecma.js
Normal file
173
Public/ecma/Drivers/WebSocketsClientsDriver.ecma.js
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import {WebSocketsClientsAbstract} from "../Abstracts/WebSocketsClientsAbstract.ecma.js";
|
||||||
|
import {Common} from "../Utils/Common.ecma.js";
|
||||||
|
import {Event} from "../Application/Event.ecma.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class WebSocketsDriver
|
||||||
|
* @constructor
|
||||||
|
* @extends WebSocketsClientsAbstract
|
||||||
|
* @param {!AnP} anp
|
||||||
|
* @param {!string} key
|
||||||
|
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||||
|
* @returns {void}
|
||||||
|
* @access public
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
export const WebSocketsClientsDriver = (function(){
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback continue_callback
|
||||||
|
* @param {boolean} ok
|
||||||
|
* @return {void}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @constructs WebSocketsClientsDriver
|
||||||
|
* @extends WebSocketsClientsAbstract
|
||||||
|
* @param {!AnP} anp
|
||||||
|
* @param {!string} key
|
||||||
|
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
const WebSocketsClientsDriver = function(anp, key, inputs){
|
||||||
|
|
||||||
|
/** @type {WebSocketsClientsDriver} */
|
||||||
|
const self = this;
|
||||||
|
/** @type {WebSocketsClientsAbstract|null} */
|
||||||
|
let _super = null,
|
||||||
|
/** @type {WebSocket|null} */
|
||||||
|
client = null,
|
||||||
|
/** @type {boolean} */
|
||||||
|
started = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const constructor = () => {
|
||||||
|
|
||||||
|
Common.extends(self, _super = new WebSocketsClientsAbstract(anp, key, inputs), false);
|
||||||
|
|
||||||
|
Common.get_value(["web_socket_autostart", "autostart"], inputs, true) && self.start();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?continue_callback} callback
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.start = (callback = null) => {
|
||||||
|
|
||||||
|
/** @type {continue_callback} */
|
||||||
|
const end = ok => Common.execute(callback, ok);
|
||||||
|
|
||||||
|
if(started){
|
||||||
|
end(false);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
started = true;
|
||||||
|
|
||||||
|
client = new WebSocket(self.url);
|
||||||
|
|
||||||
|
client.onopen = on_open;
|
||||||
|
client.onmessage = on_message
|
||||||
|
client.onerror = on_error;
|
||||||
|
client.onclose = on_close;
|
||||||
|
|
||||||
|
end(true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?continue_callback} callback
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.close = (callback = null) => {
|
||||||
|
|
||||||
|
/** @type {continue_callback} */
|
||||||
|
const end = ok => Common.execute(callback, ok);
|
||||||
|
|
||||||
|
if(!started){
|
||||||
|
end(false);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
started = false;
|
||||||
|
|
||||||
|
client.close();
|
||||||
|
client = null;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Event} _
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const on_open = _ => {
|
||||||
|
self.on_open.execute();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Event} event
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const on_message = event => {
|
||||||
|
self.on_message.execute(event.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Event} event
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const on_error = event => {
|
||||||
|
self.on_error.execute(event.error);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Event} _
|
||||||
|
* @returns {void}
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
const on_close = _ => {
|
||||||
|
self.on_close.execute();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!string} controller
|
||||||
|
* @param {!string} action
|
||||||
|
* @param {?any} [data = null]
|
||||||
|
* @param {!number} [code = 200]
|
||||||
|
* @return {void}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.send = (controller, action, data = null, code = 200) => {
|
||||||
|
client.send(Common.data_encode({
|
||||||
|
ok : code >= 200 && code < 300,
|
||||||
|
code : code,
|
||||||
|
controller : controller,
|
||||||
|
action : action,
|
||||||
|
data : data,
|
||||||
|
id : self.id
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return WebSocketsClientsDriver;
|
||||||
|
})();
|
||||||
@ -1,131 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
import {Common} from "../Utils/Common.ecma.js";
|
|
||||||
import {Event} from "../Application/Event.ecma.js";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class WebSocketsDriver
|
|
||||||
* @constructor
|
|
||||||
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
|
||||||
* @returns {void}
|
|
||||||
* @access public
|
|
||||||
* @static
|
|
||||||
*/
|
|
||||||
export const WebSocketsDriver = (function(){
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @callback continue_callback
|
|
||||||
* @param {boolean} ok
|
|
||||||
* @return {void}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @constructs WebSocketsDriver
|
|
||||||
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
|
||||||
* @returns {void}
|
|
||||||
* @access private
|
|
||||||
* @static
|
|
||||||
*/
|
|
||||||
const WebSocketsDriver = function(inputs){
|
|
||||||
|
|
||||||
/** @type {WebSocketsDriver} */
|
|
||||||
const self = this;
|
|
||||||
/** @type {WebSocket|null} */
|
|
||||||
let client = null,
|
|
||||||
/** @type {string|null} */
|
|
||||||
url = null,
|
|
||||||
/** @type {boolean} */
|
|
||||||
started = false;
|
|
||||||
|
|
||||||
/** @type {Event} */
|
|
||||||
this.on_open = new Event();
|
|
||||||
/** @type {Event} */
|
|
||||||
this.on_message = new Event();
|
|
||||||
/** @type {Event} */
|
|
||||||
this.on_error = new Event();
|
|
||||||
/** @type {Event} */
|
|
||||||
this.on_close = new Event();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {void}
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
const constructor = () => {
|
|
||||||
|
|
||||||
url = Common.get_string(inputs.url, "ws://localhost:8080");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {?continue_callback} callback
|
|
||||||
* @returns {boolean}
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
this.start = (callback = null) => {
|
|
||||||
|
|
||||||
/** @type {continue_callback} */
|
|
||||||
const end = ok => Common.execute(callback, ok);
|
|
||||||
|
|
||||||
if(started){
|
|
||||||
end(false);
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
started = true;
|
|
||||||
|
|
||||||
client = new WebSocket(url);
|
|
||||||
|
|
||||||
client.onopen = on_open;
|
|
||||||
client.onmessage = on_message
|
|
||||||
client.onerror = on_error;
|
|
||||||
client.onclose = on_close;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {?continue_callback} callback
|
|
||||||
* @returns {boolean}
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
this.close = (callback = null) => {
|
|
||||||
|
|
||||||
/** @type {continue_callback} */
|
|
||||||
const end = ok => Common.execute(callback, ok);
|
|
||||||
|
|
||||||
if(!started){
|
|
||||||
end(false);
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
started = false;
|
|
||||||
|
|
||||||
client.close();
|
|
||||||
client = null;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const on_open = event => {
|
|
||||||
console.log(["client", event]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const on_message = event => {
|
|
||||||
console.log(["message", event]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const on_error = event => {
|
|
||||||
console.log(["error", event]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const on_close = event => {
|
|
||||||
console.log(["close", event]);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.send = message => {
|
|
||||||
client.send(message);
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
return WebSocketsDriver;
|
|
||||||
})();
|
|
||||||
@ -55,9 +55,9 @@ export const ControllersManager = (function(){
|
|||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
this.update = (callback = null) => {
|
this.update = (callback = null) => {
|
||||||
|
Common.execute_array(["default_controllers_files", "controllers_files", "default_controllers", "controllers"], (key, next) => {
|
||||||
Common.execute(callback);
|
self.add(anp.settings.get(key), true, next);
|
||||||
|
}, callback, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,37 +116,50 @@ export const ControllersManager = (function(){
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @param {?any} inputs
|
* @param {?any} inputs
|
||||||
* @param {!boolean} [overwrite = false]
|
* @param {!boolean} [overwrite = false]
|
||||||
* @param {?default_callback} [callback = null]
|
* @param {?default_callback} [callback = null]
|
||||||
|
* @return {void}
|
||||||
|
* @access public
|
||||||
*/
|
*/
|
||||||
this.add = (inputs, overwrite = false, callback = null) => {
|
this.add = (inputs, overwrite = false, callback = null) => {
|
||||||
anp.files.load_json(inputs, data => {
|
anp.files.load_json(inputs, data => {
|
||||||
Object.entries(data).forEach(([key, Controller]) => {
|
data.forEach(subinputs => {
|
||||||
if(!Controller || (!overwrite && controllers[key]))
|
Object.entries(subinputs).forEach(([key, Controller]) => {
|
||||||
return;
|
if(!Controller || (!overwrite && controllers[key]))
|
||||||
if(Check.is_function(Controller))
|
return;
|
||||||
controllers[key] = new Controller(anp);
|
if(Check.is_function(Controller))
|
||||||
else if(Check.is_object(Controller))
|
controllers[key] = new Controller(anp);
|
||||||
controllers[key] = Controller;
|
else if(Check.is_object(Controller))
|
||||||
else if(Check.is_string(Controller)){
|
controllers[key] = Controller;
|
||||||
|
else if(Check.is_string(Controller)){
|
||||||
|
|
||||||
/** @type {Object.<string, any|null>|Function|null} */
|
/** @type {Object.<string, any|null>|Function|null} */
|
||||||
const Model = anp.models.get(Controller);
|
const Model = anp.models.get(Controller);
|
||||||
|
|
||||||
if(Check.is_object(Model))
|
if(Check.is_object(Model))
|
||||||
controllers[key] = Model;
|
controllers[key] = Model;
|
||||||
else if(Check.is_function(Model))
|
else if(Check.is_function(Model))
|
||||||
controllers[key] = new Model(anp);
|
controllers[key] = new Model(anp);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
Common.execute(callback);
|
Common.execute(callback);
|
||||||
}, true);
|
}, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.execute = (name, action, ...parameters) => {};
|
/**
|
||||||
|
* @param {!string} controller
|
||||||
|
* @param {!string} action
|
||||||
|
* @param {?any} [data = null]
|
||||||
|
* @param {!number} [code = 200]
|
||||||
|
* @return {void}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.execute = (controller, action, data = null, code = 200) => {
|
||||||
|
controllers[controller] && controllers[controller][action] && controllers[controller][action](data, code);
|
||||||
|
};
|
||||||
|
|
||||||
constructor();
|
constructor();
|
||||||
|
|
||||||
|
|||||||
@ -54,9 +54,9 @@ export const ModelsManager = (function(){
|
|||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
this.update = (callback = null) => {
|
this.update = (callback = null) => {
|
||||||
|
Common.execute_array(["default_models_files", "models_files", "default_models", "models"], (key, next) => {
|
||||||
Common.execute(callback);
|
self.add(anp.settings.get(key), true, next);
|
||||||
|
}, callback, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -123,11 +123,13 @@ export const ModelsManager = (function(){
|
|||||||
*/
|
*/
|
||||||
this.add = (inputs, overwrite = false, callback = null) => {
|
this.add = (inputs, overwrite = false, callback = null) => {
|
||||||
anp.files.load_json(inputs, data => {
|
anp.files.load_json(inputs, data => {
|
||||||
Object.entries(data).forEach(([key, Model]) => {
|
data.forEach(subdata => {
|
||||||
Model &&
|
Object.entries(subdata).forEach(([key, Model]) => {
|
||||||
(overwrite || !models[key]) &&
|
Model &&
|
||||||
(Check.is_function(Model) || Check.is_object(Model)) &&
|
(overwrite || !models[key]) &&
|
||||||
(models[key] = Model);
|
(Check.is_function(Model) || Check.is_object(Model)) &&
|
||||||
|
(models[key] = Model);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
Common.execute(callback);
|
Common.execute(callback);
|
||||||
}, true);
|
}, true);
|
||||||
|
|||||||
@ -168,7 +168,7 @@ export const UniqueKeysManager = (function(){
|
|||||||
* @return {string}
|
* @return {string}
|
||||||
* @access public
|
* @access public
|
||||||
*/
|
*/
|
||||||
this.create = (is_html_item = false) => {
|
this.get = (is_html_item = false) => {
|
||||||
|
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
let key;
|
let key;
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import {WebSocketClientModel} from "../Models/WebSocketClientModel.ecma.js";
|
import {WebSocketsClientsAbstract} from "../Abstracts/WebSocketsClientsAbstract.ecma.js";
|
||||||
|
import {Common} from "../Utils/Common.ecma.js";
|
||||||
|
import {Check} from "../Utils/Checks.ecma.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
|
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
|
||||||
@ -18,6 +20,24 @@ import {WebSocketClientModel} from "../Models/WebSocketClientModel.ecma.js";
|
|||||||
*/
|
*/
|
||||||
export const WebSocketsClientsManager = (function(){
|
export const WebSocketsClientsManager = (function(){
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback continue_callback
|
||||||
|
* @param {boolean} ok
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback simple_callback
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback web_socket_constructor_callback
|
||||||
|
* @param {!AnP} anp
|
||||||
|
* @param {!(Object.<string, any|null>|Array.<any|null>)} inputs
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructs WebSocketsClientsManager
|
* @constructs WebSocketsClientsManager
|
||||||
* @param {!AnP} anp
|
* @param {!AnP} anp
|
||||||
@ -31,7 +51,7 @@ export const WebSocketsClientsManager = (function(){
|
|||||||
|
|
||||||
/** @type {WebSocketsClientsManager} */
|
/** @type {WebSocketsClientsManager} */
|
||||||
const self = this,
|
const self = this,
|
||||||
/** @type {Object.<string, WebSocketClientModel} */
|
/** @type {Object.<string, WebSocketsClientsAbstract>} */
|
||||||
clients = {};
|
clients = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,10 +60,110 @@ export const WebSocketsClientsManager = (function(){
|
|||||||
*/
|
*/
|
||||||
const constructor = () => {};
|
const constructor = () => {};
|
||||||
|
|
||||||
this.add = (key, url) => {
|
/**
|
||||||
|
* @param {?continue_callback} callback
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.update = (callback = null) => {
|
||||||
|
Common.execute_array(["default_web_sockets_clients_files", "web_sockets_clients_files", "default_web_sockets_clients", "web_sockets_clients"], (key, next) => {
|
||||||
|
self.add(anp.settings.get(key), true, next);
|
||||||
|
}, callback, true);
|
||||||
|
};
|
||||||
|
|
||||||
clients[key] = new WebSocketClientModel(anp, url);
|
/**
|
||||||
|
* @param {?continue_callback} callback
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.reset = (callback = null) => {
|
||||||
|
|
||||||
|
[settings, secrets].forEach(Common.clear_dictionary);
|
||||||
|
|
||||||
|
self.update(callback);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?continue_callback} callback
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.start = (callback = null) => {
|
||||||
|
|
||||||
|
/** @type {continue_callback} */
|
||||||
|
const end = ok => Common.execute(callback, ok);
|
||||||
|
|
||||||
|
if(started){
|
||||||
|
end(false);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
started = true;
|
||||||
|
|
||||||
|
self.update(() => end(true));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?continue_callback} callback
|
||||||
|
* @returns {boolean}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.close = (callback = null) => {
|
||||||
|
|
||||||
|
/** @type {continue_callback} */
|
||||||
|
const end = ok => Common.execute(callback, ok);
|
||||||
|
|
||||||
|
if(!started){
|
||||||
|
end(false);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
started = false;
|
||||||
|
|
||||||
|
end(true);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?any} inputs
|
||||||
|
* @param {!boolean} [overwrite = false]
|
||||||
|
* @param {?simple_callback} [callback = null]
|
||||||
|
* @return {void}
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
this.add = (inputs, overwrite = false, callback = null) => {
|
||||||
|
anp.files.load_json(inputs, data => {
|
||||||
|
for(let subinputs of data)
|
||||||
|
Object.entries(subinputs).filter(([key, _]) => (
|
||||||
|
overwrite || clients[key] === undefined
|
||||||
|
)).forEach(([key, value]) => {
|
||||||
|
try{
|
||||||
|
|
||||||
|
/** @type {string|web_socket_constructor_callback|WebSocketsClientsAbstract} */
|
||||||
|
const Type = Common.get_value("type", (
|
||||||
|
Check.is_string(value) ? value = {url : value} :
|
||||||
|
value), "WebSocketsDriver"),
|
||||||
|
/** @type {web_socket_constructor_callback|null} */
|
||||||
|
Model = Check.is_string(Type) ? anp.models.get(Type) : null,
|
||||||
|
/** @type {WebSocketsClientsAbstract} */
|
||||||
|
web_socket = (
|
||||||
|
Model ? new Model(anp, key, value) :
|
||||||
|
Check.is_function(Type) ? new Type(anp, key, value) :
|
||||||
|
Type instanceof WebSocketsClientsAbstract ? Type :
|
||||||
|
null);
|
||||||
|
|
||||||
|
web_socket && (clients[key] = web_socket);
|
||||||
|
|
||||||
|
}catch(exception){
|
||||||
|
anp.exception(exception, "anp_web_sockets_clients_manager_add", {
|
||||||
|
key : key
|
||||||
|
});
|
||||||
|
};
|
||||||
|
});
|
||||||
|
Common.execute(callback);
|
||||||
|
}, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.remove = key => {
|
this.remove = key => {
|
||||||
@ -55,7 +175,45 @@ export const WebSocketsClientsManager = (function(){
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.send = (key, data) => {};
|
this.send = (key, controller, action, data = null, code = 200) => {
|
||||||
|
if(key in clients){
|
||||||
|
clients[key].send(controller, action, data, code);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.on_open = (key, callback) => {
|
||||||
|
if(key in clients){
|
||||||
|
clients[key].on_open.add(callback);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.on_message = (key, callback) => {
|
||||||
|
if(key in clients){
|
||||||
|
clients[key].on_message.add(callback);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.on_error = (key, callback) => {
|
||||||
|
if(key in clients){
|
||||||
|
clients[key].on_error.add(callback);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.on_close = (key, callback) => {
|
||||||
|
if(key in clients){
|
||||||
|
clients[key].on_close.add(callback);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
constructor();
|
constructor();
|
||||||
|
|
||||||
|
|||||||
@ -1,92 +0,0 @@
|
|||||||
"use strict";
|
|
||||||
|
|
||||||
import {Event} from "../Application/Event.ecma.js";
|
|
||||||
import {Check} from "../Utils/Checks.ecma.js";
|
|
||||||
import {Common} from "../Utils/Common.ecma.js";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const WebSocketClientModel = (function(){
|
|
||||||
|
|
||||||
const WebSocketClientModel = function(anp, inputs){
|
|
||||||
|
|
||||||
const self = this;
|
|
||||||
let web_socket = null,
|
|
||||||
url = null,
|
|
||||||
id = null;
|
|
||||||
|
|
||||||
this.on_open = new Event();
|
|
||||||
this.on_message = new Event();
|
|
||||||
this.on_close = new Event();
|
|
||||||
this.on_error = new Event();
|
|
||||||
|
|
||||||
const constructor = () => {
|
|
||||||
|
|
||||||
Check.is_string(inputs) && (inputs = {url : inputs});
|
|
||||||
|
|
||||||
web_socket = new WebSocket(url = Common.get_value("url", inputs, ""));
|
|
||||||
|
|
||||||
web_socket.onopen = self.on_open.execute;
|
|
||||||
web_socket.onmessage = self.on_message.execute;
|
|
||||||
web_socket.onclose = self.on_close.execute;
|
|
||||||
web_socket.onerror = self.on_error.execute;
|
|
||||||
|
|
||||||
// self.on_open.add(opened);
|
|
||||||
self.on_message.add(reveive_message);
|
|
||||||
self.on_close.add(closed);
|
|
||||||
self.on_error.add(error);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// const opened = event => {
|
|
||||||
// self.send("web_socket_client", "get_id", null, 200);
|
|
||||||
// };
|
|
||||||
|
|
||||||
const reveive_message = event => {
|
|
||||||
console.log(event);
|
|
||||||
|
|
||||||
const data = Common.data_decode(event.data);
|
|
||||||
|
|
||||||
switch(data.controller + "." + data.method){
|
|
||||||
case "web_socket_client.set_id":
|
|
||||||
id = data.data;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
anp.controllers.execute(data.controller, data.method, data.data, data);
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
this.send = (controller, method, data, code = 200) => {
|
|
||||||
web_socket.send(Common.data_encode({
|
|
||||||
ok : code >= 200 && code < 300,
|
|
||||||
code : code,
|
|
||||||
id : id,
|
|
||||||
controller : controller,
|
|
||||||
method : method,
|
|
||||||
data : data
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
this.close = () => {
|
|
||||||
web_socket.close();
|
|
||||||
};
|
|
||||||
|
|
||||||
const closed = event => {
|
|
||||||
id = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
const error = event => {
|
|
||||||
console.error(event);
|
|
||||||
self.close();
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
return WebSocketClientModel;
|
|
||||||
})();
|
|
||||||
@ -467,5 +467,19 @@ export const Common = (function(){
|
|||||||
"\\" + (Common.REGULAR_EXPRESSION.FROM[character] || character)
|
"\\" + (Common.REGULAR_EXPRESSION.FROM[character] || character)
|
||||||
));
|
));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Object.<string, any|null>} main
|
||||||
|
* @param {!(Object.<string, any|null>|Array.<Object.<string, any|null>>)} items
|
||||||
|
* @param {!boolean} [overwrite = false]
|
||||||
|
* @returns {void}
|
||||||
|
* @access public
|
||||||
|
* @static
|
||||||
|
*/
|
||||||
|
Common.extends = (main, items, overwrite = false) => Common.get_array(items).forEach(item => {
|
||||||
|
item && Object.entries(item).forEach(([key, value]) => {
|
||||||
|
(overwrite || !(key in main)) && (main[key] = value);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
return Common;
|
return Common;
|
||||||
})();
|
})();
|
||||||
@ -347,3 +347,9 @@ export const Body = (attributes = {}, children = []) => ["body", attributes, chi
|
|||||||
/** @type {element_callback} */
|
/** @type {element_callback} */
|
||||||
export const HTML = (attributes = {}, children = []) => ["html", attributes, children];
|
export const HTML = (attributes = {}, children = []) => ["html", attributes, children];
|
||||||
|
|
||||||
|
/** @type {element_callback} */
|
||||||
|
export const Pre = (attributes = {}, children = []) => ["pre", attributes, children];
|
||||||
|
|
||||||
|
/** @type {element_callback} */
|
||||||
|
export const Code = (attributes = {}, children = []) => ["code", attributes, children];
|
||||||
|
|
||||||
|
|||||||
101
Public/ecma/Utils/MarkDown.ecma.js
Normal file
101
Public/ecma/Utils/MarkDown.ecma.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
export const MarkDown = (function(){
|
||||||
|
|
||||||
|
const MarkDown = function(anp){};
|
||||||
|
|
||||||
|
MarkDown.Item = function(pattern, replace, block = false){
|
||||||
|
this.pattern = pattern;
|
||||||
|
this.replace = replace;
|
||||||
|
this.block = block;
|
||||||
|
this.match = null;
|
||||||
|
this.length = 0;
|
||||||
|
this.more = true;
|
||||||
|
this.index = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
MarkDown.Header = () => new MarkDown.Item(/^(#{1,6})\s*(.+)$/m, (match, hashes, content) => `<h${hashes.length}>${MarkDown.to_html(content, false)}</h${hashes.length}>`, true);
|
||||||
|
|
||||||
|
MarkDown.Block = () => new MarkDown.Item(/^```([a-z]*)\r?\n([\s\S]*?)\r?\n```/, (match, lang, content) => `<fieldset><legend>${lang}</legend><pre><code class="${lang}">${content}</code></pre></fieldset>`, true);
|
||||||
|
|
||||||
|
MarkDown.BlockQuote = () => new MarkDown.Item(/^>\s?(.+)$/m, (match, content) => `<blockquote>${MarkDown.to_html(content, false)}</blockquote>`, true);
|
||||||
|
|
||||||
|
MarkDown.Paragraph = () => new MarkDown.Item(/^((?:[^\r\n]+(?:\r\n|[\r\n])?)+)/m, (match, content) => `<p>${MarkDown.to_html(content, false)}</p>\n\n`, true);
|
||||||
|
|
||||||
|
MarkDown.Link = () => new MarkDown.Item(/\[([^\]]+)\]\(([^)]+)\)|([a-z]{2,12}:\/{2}[^ "']+)/, (match, text, url, link) => `<a href="${url || link}" target="_blank" title="${text || link}">${text || link}</a>`);
|
||||||
|
|
||||||
|
MarkDown.Bold = () => new MarkDown.Item(/\*{2}((?:(?!(?:\*{2})).)+)\*{2}/, (match, content) => `<b>${MarkDown.to_html(content, false)}</b>`);
|
||||||
|
|
||||||
|
MarkDown.Italic = () => new MarkDown.Item(/\*((?:(?!(?:\*)).|\*{2})+)\*(?!\*)/, (match, content) => `<i>${MarkDown.to_html(content, false)}</i>`);
|
||||||
|
|
||||||
|
MarkDown.to_html = (string, blocks = true) => {
|
||||||
|
|
||||||
|
let html = ``;
|
||||||
|
const matches = [
|
||||||
|
MarkDown.Header(),
|
||||||
|
MarkDown.Block(),
|
||||||
|
MarkDown.BlockQuote(),
|
||||||
|
MarkDown.Paragraph(),
|
||||||
|
MarkDown.Link(),
|
||||||
|
MarkDown.Bold(),
|
||||||
|
MarkDown.Italic()
|
||||||
|
];
|
||||||
|
|
||||||
|
do{
|
||||||
|
|
||||||
|
let index = 1 << 28,
|
||||||
|
i = null;
|
||||||
|
|
||||||
|
[...matches].forEach((item, j) => {
|
||||||
|
if(!item.more)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(item.block && !blocks){
|
||||||
|
item.more = false;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if(item.index < 0){
|
||||||
|
|
||||||
|
const submatches = string.match(item.pattern);
|
||||||
|
|
||||||
|
if(!submatches){
|
||||||
|
item.more = false;
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
item.match = submatches;
|
||||||
|
item.length = submatches[0].length;
|
||||||
|
item.index = submatches.index;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
if(index > item.index){
|
||||||
|
index = item.index;
|
||||||
|
i = j;
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
if(i === null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
const item = matches[i],
|
||||||
|
total = index + item.length;
|
||||||
|
|
||||||
|
html += string.substring(0, index) + item.replace(...item.match);
|
||||||
|
string = string.substring(total);
|
||||||
|
|
||||||
|
matches.forEach(item => {
|
||||||
|
item.index -= total;
|
||||||
|
});
|
||||||
|
|
||||||
|
}while(matches.length)
|
||||||
|
|
||||||
|
html += string;
|
||||||
|
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MarkDown;
|
||||||
|
})();
|
||||||
@ -35,13 +35,15 @@
|
|||||||
|
|
||||||
import {AnP} from "./ecma/Application/AnP.ecma.js";
|
import {AnP} from "./ecma/Application/AnP.ecma.js";
|
||||||
import {SessionsController} from "./ecma/Controllers/SessionsController.ecma.js";
|
import {SessionsController} from "./ecma/Controllers/SessionsController.ecma.js";
|
||||||
import {AIChat} from "./ecma/Controllers/AIChatController.ecma.js";
|
import {AIController} from "./ecma/Controllers/AIController.ecma.js";
|
||||||
|
import {WebSocketsClientsDriver} from "./ecma/Drivers/WebSocketsClientsDriver.ecma.js";
|
||||||
|
|
||||||
/** @type {AnP} */
|
/** @type {AnP} */
|
||||||
const anp = new AnP({
|
const anp = new AnP({
|
||||||
models : {
|
models : {
|
||||||
"sessions" : SessionsController,
|
SessionsController : SessionsController,
|
||||||
"aichat" : AIChat
|
AIController : AIController,
|
||||||
|
WebSocketsClientsDriver : WebSocketsClientsDriver
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -24,5 +24,14 @@
|
|||||||
["galego", "Galego", "/images/flags/galego.svg"],
|
["galego", "Galego", "/images/flags/galego.svg"],
|
||||||
["nihongo", "日本語", "/images/flags/nihongo.svg"],
|
["nihongo", "日本語", "/images/flags/nihongo.svg"],
|
||||||
["russkiy", "Русский", "/images/flags/russkiy.svg"]
|
["russkiy", "Русский", "/images/flags/russkiy.svg"]
|
||||||
]
|
],
|
||||||
|
"default_web_sockets_clients" : {
|
||||||
|
"anp" : {
|
||||||
|
"type" : "WebSocketsClientsDriver",
|
||||||
|
"url" : "ws://localhost:18765/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"default_controllers" : {
|
||||||
|
"ai" : "AIController"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -14,6 +14,23 @@
|
|||||||
"gui_mode" : "Modo del GUI",
|
"gui_mode" : "Modo del GUI",
|
||||||
"aichat" : "AIChat",
|
"aichat" : "AIChat",
|
||||||
"message" : "Mensaje",
|
"message" : "Mensaje",
|
||||||
"send" : "Enviar"
|
"send" : "Enviar",
|
||||||
|
"bot" : "Bot",
|
||||||
|
"waiting" : "Esperando",
|
||||||
|
"ok" : "OK",
|
||||||
|
"done" : "Hecho",
|
||||||
|
"date_from" : "Fecha de inicio",
|
||||||
|
"date_to" : "Fecha de fin",
|
||||||
|
"time" : "Tiempo",
|
||||||
|
"length" : "Longitud",
|
||||||
|
"response_tokens" : "Tokens de respuesta",
|
||||||
|
"loading" : "Cargando",
|
||||||
|
"error" : "Error",
|
||||||
|
"html" : "HTML",
|
||||||
|
"md" : "Markdown",
|
||||||
|
"status" : "Estado",
|
||||||
|
"raw_html" : "Código HTML",
|
||||||
|
"minimum" : "Mínimo",
|
||||||
|
"maximum" : "Máximo"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
110
Public/scss/AnP.aichat.scss
Normal file
110
Public/scss/AnP.aichat.scss
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
@mixin aichar-color($mode){
|
||||||
|
.aichat>legend{border-bottom-color : map-deep-get($color, $mode, "fore")}
|
||||||
|
}
|
||||||
|
.anp{
|
||||||
|
|
||||||
|
&[data-forced-gui-mode=default][data-gui-mode=default]{
|
||||||
|
@include main_color_web(light);
|
||||||
|
}
|
||||||
|
@each $key in (dark, light){
|
||||||
|
&[data-forced-gui-mode=#{$key}],&[data-forced-gui-mode=default][data-gui-mode=#{$key}]{
|
||||||
|
@include main_color_web($key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.aichat{
|
||||||
|
|
||||||
|
position : absolute;
|
||||||
|
top : 0em;
|
||||||
|
left : 0em;
|
||||||
|
width : 100%;
|
||||||
|
height : 100%;
|
||||||
|
border : none;
|
||||||
|
box-sizing : border-box;
|
||||||
|
|
||||||
|
&>legend{
|
||||||
|
padding-bottom : .1em;
|
||||||
|
border-bottom-width : .1em;
|
||||||
|
border-bottom-style : solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldset{
|
||||||
|
position : relative;
|
||||||
|
border : none;
|
||||||
|
}
|
||||||
|
legend{font-weight : 900;}
|
||||||
|
form{
|
||||||
|
display : flex;
|
||||||
|
flex-direction : row;
|
||||||
|
position : absolute;
|
||||||
|
left : 0em;
|
||||||
|
bottom : 0em;
|
||||||
|
width : 100%;
|
||||||
|
height : 5em;
|
||||||
|
box-sizing : border-box;
|
||||||
|
&>span{flex-grow : 0;}
|
||||||
|
&>button{flex-grow : 0;}
|
||||||
|
}
|
||||||
|
.messages{
|
||||||
|
position : absolute;
|
||||||
|
top : 0em;
|
||||||
|
left : 0em;
|
||||||
|
bottom : 5em;
|
||||||
|
width : 100%;
|
||||||
|
box-sizing : border-box;
|
||||||
|
overflow : auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message{
|
||||||
|
clear : both;
|
||||||
|
margin : 2em 0em;
|
||||||
|
legend{
|
||||||
|
float : left;
|
||||||
|
width : 100%;
|
||||||
|
padding : 0em;
|
||||||
|
margin-bottom : .75em;
|
||||||
|
}
|
||||||
|
nav{
|
||||||
|
position : absolute;
|
||||||
|
top : 0em;
|
||||||
|
right : 0em;
|
||||||
|
}
|
||||||
|
pre{
|
||||||
|
width : 100%;
|
||||||
|
white-space : pre-wrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-box{display : none;}
|
||||||
|
.view.buttons button{
|
||||||
|
opacity : .5;
|
||||||
|
[data-icon]::before{margin : 0em;}
|
||||||
|
[data-i18n]{display : none;}
|
||||||
|
}
|
||||||
|
[data-mode=html] .html-content,
|
||||||
|
[data-mode=raw_html] .raw-html-content,
|
||||||
|
[data-mode=md] .md-content{display : block;}
|
||||||
|
[data-mode=html] button[data-i18n=html],
|
||||||
|
[data-mode=raw_html] button[data-i18n=raw_html],
|
||||||
|
[data-mode=md] button[data-i18n=md]{opacity : 1;}
|
||||||
|
|
||||||
|
.data{
|
||||||
|
position : absolute;
|
||||||
|
right : 0em;
|
||||||
|
bottom : 0em;
|
||||||
|
margin : 0em;
|
||||||
|
padding : 0em;
|
||||||
|
list-style-type : none;
|
||||||
|
opacity : .85;
|
||||||
|
li{
|
||||||
|
display : inline-block;
|
||||||
|
margin : 0em .5em;
|
||||||
|
font-size : .75em;
|
||||||
|
[data-i18n]{display : none;}
|
||||||
|
}
|
||||||
|
[data-name=date_from]{display : none;}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -23,7 +23,10 @@
|
|||||||
width : 100%;
|
width : 100%;
|
||||||
height : 100%;
|
height : 100%;
|
||||||
overflow : hidden;
|
overflow : hidden;
|
||||||
&,input,textarea,select,button{font-family : $font-normal;}
|
&,input,textarea,select,button{
|
||||||
|
font-family : $font-normal;
|
||||||
|
box-sizing : border-box;
|
||||||
|
}
|
||||||
|
|
||||||
button,input,textarea,select{font-size : 1em;}
|
button,input,textarea,select{font-size : 1em;}
|
||||||
|
|
||||||
@ -100,6 +103,22 @@
|
|||||||
min-height : 0%;
|
min-height : 0%;
|
||||||
resize : none;
|
resize : none;
|
||||||
}
|
}
|
||||||
|
.information{
|
||||||
|
position : absolute;
|
||||||
|
bottom : 0em;
|
||||||
|
right : 0em;
|
||||||
|
font-size : .8em;
|
||||||
|
color : $color-grey;
|
||||||
|
span>[data-i18n],&>[data-value=null]{display : none;}
|
||||||
|
&>[data-i18n=minimum]::after{
|
||||||
|
content : "-";
|
||||||
|
margin : 0em .2em;
|
||||||
|
}
|
||||||
|
&>[data-i18n=maximum]::before{
|
||||||
|
content : "-";
|
||||||
|
margin : 0em .2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h1{
|
h1{
|
||||||
|
|||||||
@ -792,7 +792,8 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden; }
|
overflow: hidden; }
|
||||||
.anp, .anp input, .anp textarea, .anp select, .anp button {
|
.anp, .anp input, .anp textarea, .anp select, .anp button {
|
||||||
font-family: "Roboto"; }
|
font-family: "Roboto";
|
||||||
|
box-sizing: border-box; }
|
||||||
.anp button, .anp input, .anp textarea, .anp select {
|
.anp button, .anp input, .anp textarea, .anp select {
|
||||||
font-size: 1em; }
|
font-size: 1em; }
|
||||||
.anp a[href] {
|
.anp a[href] {
|
||||||
@ -889,6 +890,20 @@
|
|||||||
min-width: 0%;
|
min-width: 0%;
|
||||||
min-height: 0%;
|
min-height: 0%;
|
||||||
resize: none; }
|
resize: none; }
|
||||||
|
.anp .input .information {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0em;
|
||||||
|
right: 0em;
|
||||||
|
font-size: .8em;
|
||||||
|
color: #898989; }
|
||||||
|
.anp .input .information span > [data-i18n], .anp .input .information > [data-value=null] {
|
||||||
|
display: none; }
|
||||||
|
.anp .input .information > [data-i18n=minimum]::after {
|
||||||
|
content: "-";
|
||||||
|
margin: 0em .2em; }
|
||||||
|
.anp .input .information > [data-i18n=maximum]::before {
|
||||||
|
content: "-";
|
||||||
|
margin: 0em .2em; }
|
||||||
.anp h1 {
|
.anp h1 {
|
||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
@ -1053,5 +1068,137 @@
|
|||||||
content: "\f689"; }
|
content: "\f689"; }
|
||||||
.anp [data-icon=gui_mode]::before {
|
.anp [data-icon=gui_mode]::before {
|
||||||
content: "\f043"; }
|
content: "\f043"; }
|
||||||
|
.anp [data-icon=html]::before {
|
||||||
|
content: "\f13b";
|
||||||
|
font-family: "FA6FB"; }
|
||||||
|
.anp [data-icon=raw_html]::before {
|
||||||
|
content: "\f121"; }
|
||||||
|
.anp [data-icon=md]::before {
|
||||||
|
content: "\f1c9"; }
|
||||||
|
|
||||||
|
.anp[data-forced-gui-mode=default][data-gui-mode=default] {
|
||||||
|
background-color: #EFEFEF;
|
||||||
|
color: #222; }
|
||||||
|
.anp[data-forced-gui-mode=default][data-gui-mode=default] a[href], .anp[data-forced-gui-mode=default][data-gui-mode=default] [data-role=link], .anp[data-forced-gui-mode=default][data-gui-mode=default] button, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=submit], .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=button], .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=reset], .anp[data-forced-gui-mode=default][data-gui-mode=default] [role=button] {
|
||||||
|
color: #2262b0; }
|
||||||
|
.anp[data-forced-gui-mode=default][data-gui-mode=default] a[href]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [data-role=link]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] button:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=submit]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=reset]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [role=button]:hover {
|
||||||
|
color: #b06222; }
|
||||||
|
.anp[data-forced-gui-mode=default][data-gui-mode=default] button, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=submit], .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=button], .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=reset], .anp[data-forced-gui-mode=default][data-gui-mode=default] [role=button] {
|
||||||
|
border-color: #2262b0;
|
||||||
|
box-shadow: 0em 0em 0.2em inset #2262b0; }
|
||||||
|
.anp[data-forced-gui-mode=default][data-gui-mode=default] button:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=submit]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [type=reset]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=default] [role=button]:hover {
|
||||||
|
border-color: #b06222;
|
||||||
|
box-shadow: 0em 0em 0.2em inset #b06222; }
|
||||||
|
.anp[data-forced-gui-mode=dark], .anp[data-forced-gui-mode=default][data-gui-mode=dark] {
|
||||||
|
background-color: #222;
|
||||||
|
color: #EFEFEF; }
|
||||||
|
.anp[data-forced-gui-mode=dark] a[href], .anp[data-forced-gui-mode=dark] [data-role=link], .anp[data-forced-gui-mode=dark] button, .anp[data-forced-gui-mode=dark] [type=submit], .anp[data-forced-gui-mode=dark] [type=button], .anp[data-forced-gui-mode=dark] [type=reset], .anp[data-forced-gui-mode=dark] [role=button], .anp[data-forced-gui-mode=default][data-gui-mode=dark] a[href], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [data-role=link], .anp[data-forced-gui-mode=default][data-gui-mode=dark] button, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=submit], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=button], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=reset], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [role=button] {
|
||||||
|
color: #4b8bd9; }
|
||||||
|
.anp[data-forced-gui-mode=dark] a[href]:hover, .anp[data-forced-gui-mode=dark] [data-role=link]:hover, .anp[data-forced-gui-mode=dark] button:hover, .anp[data-forced-gui-mode=dark] [type=submit]:hover, .anp[data-forced-gui-mode=dark] [type=button]:hover, .anp[data-forced-gui-mode=dark] [type=reset]:hover, .anp[data-forced-gui-mode=dark] [role=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] a[href]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [data-role=link]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] button:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=submit]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=reset]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [role=button]:hover {
|
||||||
|
color: #d98b4b; }
|
||||||
|
.anp[data-forced-gui-mode=dark] button, .anp[data-forced-gui-mode=dark] [type=submit], .anp[data-forced-gui-mode=dark] [type=button], .anp[data-forced-gui-mode=dark] [type=reset], .anp[data-forced-gui-mode=dark] [role=button], .anp[data-forced-gui-mode=default][data-gui-mode=dark] button, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=submit], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=button], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=reset], .anp[data-forced-gui-mode=default][data-gui-mode=dark] [role=button] {
|
||||||
|
border-color: #4b8bd9;
|
||||||
|
box-shadow: 0em 0em 0.2em inset #4b8bd9; }
|
||||||
|
.anp[data-forced-gui-mode=dark] button:hover, .anp[data-forced-gui-mode=dark] [type=submit]:hover, .anp[data-forced-gui-mode=dark] [type=button]:hover, .anp[data-forced-gui-mode=dark] [type=reset]:hover, .anp[data-forced-gui-mode=dark] [role=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] button:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=submit]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [type=reset]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=dark] [role=button]:hover {
|
||||||
|
border-color: #d98b4b;
|
||||||
|
box-shadow: 0em 0em 0.2em inset #d98b4b; }
|
||||||
|
.anp[data-forced-gui-mode=light], .anp[data-forced-gui-mode=default][data-gui-mode=light] {
|
||||||
|
background-color: #EFEFEF;
|
||||||
|
color: #222; }
|
||||||
|
.anp[data-forced-gui-mode=light] a[href], .anp[data-forced-gui-mode=light] [data-role=link], .anp[data-forced-gui-mode=light] button, .anp[data-forced-gui-mode=light] [type=submit], .anp[data-forced-gui-mode=light] [type=button], .anp[data-forced-gui-mode=light] [type=reset], .anp[data-forced-gui-mode=light] [role=button], .anp[data-forced-gui-mode=default][data-gui-mode=light] a[href], .anp[data-forced-gui-mode=default][data-gui-mode=light] [data-role=link], .anp[data-forced-gui-mode=default][data-gui-mode=light] button, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=submit], .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=button], .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=reset], .anp[data-forced-gui-mode=default][data-gui-mode=light] [role=button] {
|
||||||
|
color: #2262b0; }
|
||||||
|
.anp[data-forced-gui-mode=light] a[href]:hover, .anp[data-forced-gui-mode=light] [data-role=link]:hover, .anp[data-forced-gui-mode=light] button:hover, .anp[data-forced-gui-mode=light] [type=submit]:hover, .anp[data-forced-gui-mode=light] [type=button]:hover, .anp[data-forced-gui-mode=light] [type=reset]:hover, .anp[data-forced-gui-mode=light] [role=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] a[href]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [data-role=link]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] button:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=submit]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=reset]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [role=button]:hover {
|
||||||
|
color: #b06222; }
|
||||||
|
.anp[data-forced-gui-mode=light] button, .anp[data-forced-gui-mode=light] [type=submit], .anp[data-forced-gui-mode=light] [type=button], .anp[data-forced-gui-mode=light] [type=reset], .anp[data-forced-gui-mode=light] [role=button], .anp[data-forced-gui-mode=default][data-gui-mode=light] button, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=submit], .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=button], .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=reset], .anp[data-forced-gui-mode=default][data-gui-mode=light] [role=button] {
|
||||||
|
border-color: #2262b0;
|
||||||
|
box-shadow: 0em 0em 0.2em inset #2262b0; }
|
||||||
|
.anp[data-forced-gui-mode=light] button:hover, .anp[data-forced-gui-mode=light] [type=submit]:hover, .anp[data-forced-gui-mode=light] [type=button]:hover, .anp[data-forced-gui-mode=light] [type=reset]:hover, .anp[data-forced-gui-mode=light] [role=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] button:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=submit]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=button]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [type=reset]:hover, .anp[data-forced-gui-mode=default][data-gui-mode=light] [role=button]:hover {
|
||||||
|
border-color: #b06222;
|
||||||
|
box-shadow: 0em 0em 0.2em inset #b06222; }
|
||||||
|
.anp .aichat {
|
||||||
|
position: absolute;
|
||||||
|
top: 0em;
|
||||||
|
left: 0em;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
box-sizing: border-box; }
|
||||||
|
.anp .aichat > legend {
|
||||||
|
padding-bottom: .1em;
|
||||||
|
border-bottom-width: .1em;
|
||||||
|
border-bottom-style: solid; }
|
||||||
|
.anp .aichat fieldset {
|
||||||
|
position: relative;
|
||||||
|
border: none; }
|
||||||
|
.anp .aichat legend {
|
||||||
|
font-weight: 900; }
|
||||||
|
.anp .aichat form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
position: absolute;
|
||||||
|
left: 0em;
|
||||||
|
bottom: 0em;
|
||||||
|
width: 100%;
|
||||||
|
height: 5em;
|
||||||
|
box-sizing: border-box; }
|
||||||
|
.anp .aichat form > span {
|
||||||
|
flex-grow: 0; }
|
||||||
|
.anp .aichat form > button {
|
||||||
|
flex-grow: 0; }
|
||||||
|
.anp .aichat .messages {
|
||||||
|
position: absolute;
|
||||||
|
top: 0em;
|
||||||
|
left: 0em;
|
||||||
|
bottom: 5em;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: auto; }
|
||||||
|
.anp .aichat .message {
|
||||||
|
clear: both;
|
||||||
|
margin: 2em 0em; }
|
||||||
|
.anp .aichat .message legend {
|
||||||
|
float: left;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0em;
|
||||||
|
margin-bottom: .75em; }
|
||||||
|
.anp .aichat .message nav {
|
||||||
|
position: absolute;
|
||||||
|
top: 0em;
|
||||||
|
right: 0em; }
|
||||||
|
.anp .aichat .message pre {
|
||||||
|
width: 100%;
|
||||||
|
white-space: pre-wrap; }
|
||||||
|
.anp .aichat .message-box {
|
||||||
|
display: none; }
|
||||||
|
.anp .aichat .view.buttons button {
|
||||||
|
opacity: .5; }
|
||||||
|
.anp .aichat .view.buttons button [data-icon]::before {
|
||||||
|
margin: 0em; }
|
||||||
|
.anp .aichat .view.buttons button [data-i18n] {
|
||||||
|
display: none; }
|
||||||
|
.anp .aichat [data-mode=html] .html-content,
|
||||||
|
.anp .aichat [data-mode=raw_html] .raw-html-content,
|
||||||
|
.anp .aichat [data-mode=md] .md-content {
|
||||||
|
display: block; }
|
||||||
|
.anp .aichat [data-mode=html] button[data-i18n=html],
|
||||||
|
.anp .aichat [data-mode=raw_html] button[data-i18n=raw_html],
|
||||||
|
.anp .aichat [data-mode=md] button[data-i18n=md] {
|
||||||
|
opacity: 1; }
|
||||||
|
.anp .aichat .data {
|
||||||
|
position: absolute;
|
||||||
|
right: 0em;
|
||||||
|
bottom: 0em;
|
||||||
|
margin: 0em;
|
||||||
|
padding: 0em;
|
||||||
|
list-style-type: none;
|
||||||
|
opacity: .85; }
|
||||||
|
.anp .aichat .data li {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0em .5em;
|
||||||
|
font-size: .75em; }
|
||||||
|
.anp .aichat .data li [data-i18n] {
|
||||||
|
display: none; }
|
||||||
|
.anp .aichat .data [data-name=date_from] {
|
||||||
|
display: none; }
|
||||||
|
|
||||||
/*# sourceMappingURL=AnP.css.map */
|
/*# sourceMappingURL=AnP.css.map */
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1,4 +1,5 @@
|
|||||||
.anp{
|
.anp{
|
||||||
|
|
||||||
[data-icon]::before{
|
[data-icon]::before{
|
||||||
margin-right : .3em;
|
margin-right : .3em;
|
||||||
font-family : $font-icon;
|
font-family : $font-icon;
|
||||||
@ -13,4 +14,10 @@
|
|||||||
[data-icon=zoom]::before{content : unicode("f002");}
|
[data-icon=zoom]::before{content : unicode("f002");}
|
||||||
[data-icon=reset_zoom]::before{content : unicode("f689");}
|
[data-icon=reset_zoom]::before{content : unicode("f689");}
|
||||||
[data-icon=gui_mode]::before{content : unicode("f043");}
|
[data-icon=gui_mode]::before{content : unicode("f043");}
|
||||||
|
|
||||||
|
// Icons for AI Chat
|
||||||
|
[data-icon=html]::before{content : unicode("f13b"); font-family : "FA6FB";}
|
||||||
|
[data-icon=raw_html]::before{content : unicode("f121");}
|
||||||
|
[data-icon=md]::before{content : unicode("f1c9");}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1 +1 @@
|
|||||||
@import "AnP.fonts.scss", "AnP.settings.scss", "AnP.common.scss", "AnP.base.scss", "AnP.icons.scss";
|
@import "AnP.fonts.scss", "AnP.settings.scss", "AnP.common.scss", "AnP.base.scss", "AnP.icons.scss", "AnP.aichat.scss";
|
||||||
@ -30,6 +30,8 @@ class AIInterpretersAbstract(ABC):
|
|||||||
self.pool:str = self.anp.settings.get(("ai_interpreter_pool", "ai_pool", "pool"), inputs, self.key)
|
self.pool:str = self.anp.settings.get(("ai_interpreter_pool", "ai_pool", "pool"), inputs, self.key)
|
||||||
self.sessions:dict[int, list[int]] = {}
|
self.sessions:dict[int, list[int]] = {}
|
||||||
self.sessions_i:int = 0
|
self.sessions_i:int = 0
|
||||||
|
self.think:bool = self.anp.settings.get(("ai_interpreter_think", "ai_think", "think"), inputs, False)
|
||||||
|
self.allow_contexts:bool = self.anp.settings.get(("ai_interpreter_allow_contexts", "ai_allow_contexts", "allow_contexts"), inputs, True)
|
||||||
|
|
||||||
def start(self:Self) -> None:
|
def start(self:Self) -> None:
|
||||||
pass
|
pass
|
||||||
@ -47,7 +49,7 @@ class AIInterpretersAbstract(ABC):
|
|||||||
return id, self.sessions[id]
|
return id, self.sessions[id]
|
||||||
|
|
||||||
def save_context(self:Self, id:int, context:list[int]) -> None:
|
def save_context(self:Self, id:int, context:list[int]) -> None:
|
||||||
if id in self.sessions:
|
if self.allow_contexts and id in self.sessions:
|
||||||
self.sessions[id] = context
|
self.sessions[id] = context
|
||||||
|
|
||||||
def close_session(self:Self, id:int) -> bool:
|
def close_session(self:Self, id:int) -> bool:
|
||||||
@ -56,12 +58,15 @@ class AIInterpretersAbstract(ABC):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_orders(self:Self, orders:str|list[str]) -> str:
|
def get_context(self:Self, id:int) -> list[int]:
|
||||||
|
return self.sessions[id] if id in self.sessions else []
|
||||||
|
|
||||||
|
def get_orders(self:Self, orders:Optional[str|list[str]] = None) -> str:
|
||||||
|
|
||||||
results:str = ""
|
results:str = ""
|
||||||
i:int = 0
|
i:int = 0
|
||||||
|
|
||||||
for block in (orders, self.orders):
|
for block in (self.orders, orders):
|
||||||
if block:
|
if block:
|
||||||
if Check.is_array(block):
|
if Check.is_array(block):
|
||||||
|
|
||||||
@ -73,10 +78,13 @@ class AIInterpretersAbstract(ABC):
|
|||||||
else:
|
else:
|
||||||
results += ("\n\n" if results else "") + str(block).strip()
|
results += ("\n\n" if results else "") + str(block).strip()
|
||||||
|
|
||||||
|
return results
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def request(self:Self,
|
def request(self:Self,
|
||||||
session:int|None,
|
session:int|None,
|
||||||
message:str,
|
message:str,
|
||||||
orders:list[str] = [],
|
orders:list[str] = [],
|
||||||
callback:Optional[Callable[[int, AIResponseModel], None]] = None
|
callback:Optional[Callable[[int, AIResponseModel], None]] = None,
|
||||||
|
context:list[int] = []
|
||||||
) -> tuple[int|None, AIResponseModel]:pass
|
) -> tuple[int|None, AIResponseModel]:pass
|
||||||
@ -9,8 +9,11 @@ from Utils.Common import Common
|
|||||||
|
|
||||||
class WebSocketServersAbstract(ABC):
|
class WebSocketServersAbstract(ABC):
|
||||||
|
|
||||||
def __init__(self:Self, anp:AnPInterface, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
||||||
self.anp:AnPInterface = anp
|
self.anp:AnPInterface = anp
|
||||||
|
self.key:str = key
|
||||||
|
self.host:str = self.anp.settings.get(("web_socket_server_host", "host"), inputs, "")
|
||||||
|
self.port:int = self.anp.settings.get(("web_socket_server_port", "port"), inputs, 18765)
|
||||||
self.on_new_client:Event = Event()
|
self.on_new_client:Event = Event()
|
||||||
self.on_message:Event = Event()
|
self.on_message:Event = Event()
|
||||||
self.on_close:Event = Event()
|
self.on_close:Event = Event()
|
||||||
@ -25,14 +28,15 @@ class WebSocketServersAbstract(ABC):
|
|||||||
@abstractmethod
|
@abstractmethod
|
||||||
def close_client(self:Self, id:int) -> None:pass
|
def close_client(self:Self, id:int) -> None:pass
|
||||||
|
|
||||||
def format_data(self:Self, controller:str, method:str, data:Any|None, id:str, code:int = 200) -> str:
|
def format_data(self:Self, controller:str, action:str, data:Any|None, id:str, code:int = 200) -> str:
|
||||||
return Common.data_encode({
|
return Common.data_encode({
|
||||||
|
"ok" : code >= 200 and code < 300,
|
||||||
|
"code" : code,
|
||||||
"controller": controller,
|
"controller": controller,
|
||||||
"method": method,
|
"action": action,
|
||||||
"data": data,
|
"data": data,
|
||||||
"id": id,
|
"id": id
|
||||||
"code": code
|
|
||||||
})
|
})
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def send(self:Self, controller:str, method:str, data:Any|None, ids:Optional[int|Sequence[int]] = None, code:int = 200) -> None:pass
|
def send(self:Self, controller:str, action:str, data:Any|None, ids:Optional[str|Sequence[str]] = None, code:int = 200) -> None:pass
|
||||||
@ -10,20 +10,23 @@ from Models.PseudoLoRAModel import PseudoLoRAModel
|
|||||||
class AIController(ControllerAbstract, ModelAbstract):
|
class AIController(ControllerAbstract, ModelAbstract):
|
||||||
|
|
||||||
def __test_execution(self:Self, end:Callable[[], None], request:RequestModel) -> None:
|
def __test_execution(self:Self, end:Callable[[], None], request:RequestModel) -> None:
|
||||||
print("PASA")
|
|
||||||
self.anp.ai_interpreters.request(
|
self.anp.ai_interpreters.request(
|
||||||
"anp_titles",
|
"anp_responses",
|
||||||
None,
|
None,
|
||||||
request.get("message", "Hola, Gemma. ¿Me puedes ayudar a instalar una impresora Canon?"),
|
request.get("message", "Hola, Gemma. ¿Me puedes ayudar a instalar una impresora Canon?"),
|
||||||
lambda id, response: print((id, response.response)),
|
# lambda id, response: print((id, response.response, request.get("client_id"))),
|
||||||
[
|
lambda id, response: self.anp.web_socket_servers.send("anp", "ai", "test", {
|
||||||
"Seleccionar títulos exactos relacionados con la consulta:" + "".join(
|
"id" : id,
|
||||||
"\n - " + title for title in [
|
"response" : response.response
|
||||||
"Información, gestión e instalación de Cividas",
|
}, request.get("client_id")),
|
||||||
"Información, gestión e instalación de Impresoras/Fotocopiadoras/Multifuncionales Canon"
|
# [
|
||||||
]
|
# "# Títulos\n" + "".join(
|
||||||
),
|
# "\n - " + title for title in [
|
||||||
]
|
# "Información, gestión e instalación de Cividas",
|
||||||
|
# "Información, gestión e instalación de Impresoras/Fotocopiadoras/Multifuncionales Canon"
|
||||||
|
# ]
|
||||||
|
# ),
|
||||||
|
# ]
|
||||||
)
|
)
|
||||||
end()
|
end()
|
||||||
|
|
||||||
@ -34,3 +37,26 @@ class AIController(ControllerAbstract, ModelAbstract):
|
|||||||
"code" : 200,
|
"code" : 200,
|
||||||
"message" : "ok"
|
"message" : "ok"
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def __message_execution(self:Self, end:Callable[[], None], request:RequestModel) -> None:
|
||||||
|
self.anp.ai_interpreters.request(
|
||||||
|
"anp_responses",
|
||||||
|
None,
|
||||||
|
request.get("message"),
|
||||||
|
lambda id, response: self.anp.web_socket_servers.send("anp", "ai", "message", {
|
||||||
|
"id" : id,
|
||||||
|
"response" : response.response,
|
||||||
|
"ok" : response.ok,
|
||||||
|
"done" : response.done,
|
||||||
|
"data_id" : request.get("message_id")
|
||||||
|
}, request.get("client_id"))
|
||||||
|
)
|
||||||
|
end()
|
||||||
|
|
||||||
|
def message(self:Self, request:RequestModel) -> None:
|
||||||
|
self.anp.queues.add("anp", self.__message_execution, request)
|
||||||
|
request.set_response({
|
||||||
|
"ok" : True,
|
||||||
|
"code" : 200,
|
||||||
|
"message" : "ok"
|
||||||
|
})
|
||||||
@ -24,7 +24,8 @@ class OllamaDriver(AIInterpretersAbstract, ModelAbstract):
|
|||||||
session:int|None,
|
session:int|None,
|
||||||
message:str,
|
message:str,
|
||||||
callback:Optional[Callable[[int, AIResponseModel], None]] = None,
|
callback:Optional[Callable[[int, AIResponseModel], None]] = None,
|
||||||
orders:str|list[str] = []
|
orders:str|list[str] = [],
|
||||||
|
custom_context:Optional[list[int]] = None
|
||||||
) -> tuple[int|None, AIResponseModel]:
|
) -> tuple[int|None, AIResponseModel]:
|
||||||
|
|
||||||
response:Response
|
response:Response
|
||||||
@ -38,14 +39,18 @@ class OllamaDriver(AIInterpretersAbstract, ModelAbstract):
|
|||||||
if self.maximum_tokens_per_session is not None:
|
if self.maximum_tokens_per_session is not None:
|
||||||
options["num_ctx"] = self.maximum_tokens_per_session
|
options["num_ctx"] = self.maximum_tokens_per_session
|
||||||
|
|
||||||
session, context = self.get_session(session)
|
session, context = custom_context or self.get_session(session)
|
||||||
orders = self.get_orders(orders)
|
orders = self.get_orders(orders)
|
||||||
|
|
||||||
|
if custom_context:
|
||||||
|
context = context.copy()
|
||||||
|
|
||||||
with Post(self.url, json = {
|
with Post(self.url, json = {
|
||||||
"model" : self.model,
|
"model" : self.model,
|
||||||
"prompt": message,
|
"prompt": message,
|
||||||
**({"system": orders} if len(orders) else {}),
|
**({"system": orders} if len(orders) else {}),
|
||||||
"stream": self.stream,
|
"stream": self.stream,
|
||||||
|
"think" : self.think,
|
||||||
**(
|
**(
|
||||||
{"format" : self.format} if (
|
{"format" : self.format} if (
|
||||||
self.format == "json" or
|
self.format == "json" or
|
||||||
@ -65,8 +70,9 @@ class OllamaDriver(AIInterpretersAbstract, ModelAbstract):
|
|||||||
chunk:bytes
|
chunk:bytes
|
||||||
|
|
||||||
for chunk in response.iter_lines():
|
for chunk in response.iter_lines():
|
||||||
|
if not self.anp.working():
|
||||||
|
break
|
||||||
if chunk:
|
if chunk:
|
||||||
print(Common.json_decode(chunk))
|
|
||||||
results.update(Common.json_decode(chunk))
|
results.update(Common.json_decode(chunk))
|
||||||
if results.done:
|
if results.done:
|
||||||
self.save_context(session, results.context)
|
self.save_context(session, results.context)
|
||||||
|
|||||||
@ -12,19 +12,17 @@ from Utils.Checks import Check
|
|||||||
|
|
||||||
class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
|
class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
|
||||||
|
|
||||||
def __init__(self:Self, anp:AnPInterface, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
def __init__(self:Self, anp:AnPInterface, key:str, inputs:Optional[dict[str, Any|None]|Sequence[Any|None]] = None) -> None:
|
||||||
super().__init__(anp, inputs)
|
super().__init__(anp, key, inputs)
|
||||||
|
|
||||||
self.__server:WebSocketServer
|
self.__server:WebSocketServer
|
||||||
self.__clients:dict[str, WebSocketClient] = {}
|
self.__clients:dict[str, WebSocketClient] = {}
|
||||||
self.__host:str = anp.settings.get(("web_socket_server_host", "host"), inputs, "")
|
|
||||||
self.__port:int = anp.settings.get(("web_socket_server_port", "port"), inputs, 8765)
|
|
||||||
self.__thread:Thread = None
|
self.__thread:Thread = None
|
||||||
|
|
||||||
anp.settings.get(("web_socket_server_autostart", "autostart"), inputs, True) and self.start()
|
anp.settings.get(("web_socket_server_autostart", "autostart"), inputs, True) and self.start()
|
||||||
|
|
||||||
def __run(self:Self) -> None:
|
def __run(self:Self) -> None:
|
||||||
self.__server = server_serve(self.__handler, self.__host, self.__port)
|
self.__server = server_serve(self.__handler, self.host, self.port)
|
||||||
self.__server.serve_forever()
|
self.__server.serve_forever()
|
||||||
|
|
||||||
def start(self:Self) -> None:
|
def start(self:Self) -> None:
|
||||||
@ -40,27 +38,34 @@ class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
|
|||||||
|
|
||||||
self.__server.shutdown()
|
self.__server.shutdown()
|
||||||
|
|
||||||
def close_client(self:Self, id:int) -> None:
|
def close_client(self:Self, ids:Optional[str|list[str]] = None) -> None:
|
||||||
if id in self.__clients:
|
|
||||||
try:
|
id:str
|
||||||
self.__clients[id].close()
|
|
||||||
except Exception as exception:
|
for id in (
|
||||||
self.anp.exception(exception, "web_socket_server_client_close_exception", {
|
ids if Check.is_array(ids) else
|
||||||
"client": id,
|
list(self.__clients.keys()) if ids is None else
|
||||||
|
[ids] if Check.is_string(ids) else
|
||||||
|
[]):
|
||||||
|
if id in self.__clients:
|
||||||
|
try:
|
||||||
|
self.__clients[id].close()
|
||||||
|
except Exception as exception:
|
||||||
|
self.anp.exception(exception, "web_socket_server_client_close_exception", {
|
||||||
|
"id": id,
|
||||||
"port": self.port,
|
"port": self.port,
|
||||||
"host": self.host
|
"host": self.host
|
||||||
})
|
})
|
||||||
del self.__clients[id]
|
|
||||||
|
|
||||||
def __handler(self:Self, client:WebSocketClient) -> None:
|
def __handler(self:Self, client:WebSocketClient) -> None:
|
||||||
|
|
||||||
id:int = self.anp.unique_keys.create()
|
id:str = self.anp.unique_keys.get()
|
||||||
|
|
||||||
self.__clients[id] = client
|
self.__clients[id] = client
|
||||||
self.on_new_client.execute(id)
|
self.on_new_client.execute(id)
|
||||||
|
|
||||||
self.anp.print("info", "web_socket_server_client_connected", {
|
self.anp.print("info", "web_socket_server_client_connected", {
|
||||||
"client": id,
|
"id": id,
|
||||||
"port": self.port,
|
"port": self.port,
|
||||||
"host": self.host,
|
"host": self.host,
|
||||||
"client_host" : client.remote_address[0],
|
"client_host" : client.remote_address[0],
|
||||||
@ -76,26 +81,30 @@ class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
|
|||||||
break
|
break
|
||||||
self.on_message.execute(id, message)
|
self.on_message.execute(id, message)
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
self.anp.exception(exception, "web_socket_server_client_exception", {
|
self.anp.working() and self.anp.exception(exception, "web_socket_server_client_exception", {
|
||||||
"client": id,
|
"id": id,
|
||||||
"port": self.port,
|
"port": self.port,
|
||||||
"host": self.host
|
"host": self.host
|
||||||
})
|
})
|
||||||
self.on_error.execute(id, exception)
|
self.on_error.execute(id, exception)
|
||||||
finally:
|
finally:
|
||||||
self.close_client(id)
|
try:
|
||||||
|
self.__clients[id].close()
|
||||||
|
except Exception as _:
|
||||||
|
pass
|
||||||
|
del self.__clients[id]
|
||||||
self.anp.unique_keys.remove(id)
|
self.anp.unique_keys.remove(id)
|
||||||
self.on_close.execute(id)
|
self.on_close.execute(id)
|
||||||
self.anp.print("info", "web_socket_server_client_disconnected", {
|
self.anp.print("info", "web_socket_server_client_disconnected", {
|
||||||
"client": id,
|
"id": id,
|
||||||
"port": self.port,
|
"port": self.port,
|
||||||
"host": self.host
|
"host": self.host
|
||||||
})
|
})
|
||||||
|
|
||||||
def send(self:Self, controller:str, method:str, data:str, ids:Optional[int|Sequence[int]] = None, code:int = 200) -> bool:
|
def send(self:Self, controller:str, action:str, data:str, ids:Optional[str|Sequence[str]] = None, code:int = 200) -> bool:
|
||||||
|
|
||||||
success:bool = True
|
success:bool = True
|
||||||
id:int
|
id:str
|
||||||
|
|
||||||
for id in (
|
for id in (
|
||||||
list(self.__clients.keys()) if ids is None else
|
list(self.__clients.keys()) if ids is None else
|
||||||
@ -103,10 +112,10 @@ class WebSocketServerDriver(WebSocketServersAbstract, ModelAbstract):
|
|||||||
[ids]):
|
[ids]):
|
||||||
if id in self.__clients:
|
if id in self.__clients:
|
||||||
try:
|
try:
|
||||||
self.__clients[id].send(self.format_data(controller, method, data, id, code))
|
self.__clients[id].send(self.format_data(controller, action, data, id, code))
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
self.anp.exception(exception, "web_socket_server_client_send_exception", {
|
self.anp.exception(exception, "web_socket_server_client_send_exception", {
|
||||||
"client": id,
|
"id": id,
|
||||||
"port": self.port,
|
"port": self.port,
|
||||||
"host": self.host
|
"host": self.host
|
||||||
})
|
})
|
||||||
|
|||||||
@ -49,10 +49,10 @@ class WebSocketServersManager:
|
|||||||
|
|
||||||
self.__web_sockets[name] = web_socket
|
self.__web_sockets[name] = web_socket
|
||||||
|
|
||||||
web_socket.on_new_client.add(lambda id:self.on_new_client(web_socket, id, name))
|
web_socket.on_new_client.add(lambda id:self.on_new_client.execute(web_socket, id, name))
|
||||||
web_socket.on_message.add(lambda id, message:self.on_message(web_socket, id, message, name))
|
web_socket.on_message.add(lambda id, message:self.on_message.execute(web_socket, id, message, name))
|
||||||
web_socket.on_close.add(lambda id:self.on_close(web_socket, id, name))
|
web_socket.on_close.add(lambda id:self.on_close.execute(web_socket, id, name))
|
||||||
web_socket.on_error.add(lambda id, exception:self.on_error(web_socket, id, exception, name))
|
web_socket.on_error.add(lambda id, exception:self.on_error.execute(web_socket, id, exception, name))
|
||||||
|
|
||||||
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:
|
def add(self:Self, inputs:Any|None, overwrite:bool = False) -> None:
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ class WebSocketServersManager:
|
|||||||
|
|
||||||
Class:type[WebSocketServersAbstract] = self.anp.models.get(WebSocketServersAbstract, _type)
|
Class:type[WebSocketServersAbstract] = self.anp.models.get(WebSocketServersAbstract, _type)
|
||||||
|
|
||||||
Class and issubclass(Class, WebSocketServersAbstract) and self.__set(key, Class(self.anp, value))
|
Class and issubclass(Class, WebSocketServersAbstract) and self.__set(key, Class(self.anp, key, value))
|
||||||
|
|
||||||
def remove(self:Self, names:str|Sequence[str]) -> None:
|
def remove(self:Self, names:str|Sequence[str]) -> None:
|
||||||
for name in Common.get_keys(names):
|
for name in Common.get_keys(names):
|
||||||
@ -94,20 +94,14 @@ class WebSocketServersManager:
|
|||||||
def send(self:Self,
|
def send(self:Self,
|
||||||
name:str,
|
name:str,
|
||||||
controller:str,
|
controller:str,
|
||||||
method:str,
|
action:str,
|
||||||
data:Optional[Any] = None,
|
data:Optional[Any] = None,
|
||||||
clients:Optional[int|Sequence[int]] = None,
|
clients:Optional[str|Sequence[str]] = None,
|
||||||
code:int = 200
|
code:int = 200
|
||||||
) -> None:
|
) -> None:
|
||||||
if name in self.__web_sockets:
|
if name in self.__web_sockets:
|
||||||
try:
|
try:
|
||||||
self.__web_sockets[name].send(Common.data_encode({
|
self.__web_sockets[name].send(controller, action, data, clients, code)
|
||||||
"ok" : code >= 200 and code < 300,
|
|
||||||
"code" : code,
|
|
||||||
"controller" : controller,
|
|
||||||
"method" : method,
|
|
||||||
"data" : data
|
|
||||||
}), clients)
|
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
self.anp.exception(exception, "web_socket_server_send_exception", {"name": name})
|
self.anp.exception(exception, "web_socket_server_send_exception", {"name": name})
|
||||||
|
|
||||||
@ -115,10 +109,12 @@ class WebSocketServersManager:
|
|||||||
|
|
||||||
data:dict[str, Any|None] = Common.data_decode(raw_data)
|
data:dict[str, Any|None] = Common.data_decode(raw_data)
|
||||||
|
|
||||||
if "controller" in data and "method" in data:
|
if "controller" in data and "action" in data:
|
||||||
|
|
||||||
request:RequestModel = RequestModel()
|
request:RequestModel = RequestModel()
|
||||||
|
|
||||||
|
"data" in data and Check.is_dictionary(data["data"]) and request.set_variables(data["data"])
|
||||||
|
|
||||||
request.data = data.get("data", None)
|
request.data = data.get("data", None)
|
||||||
request.variables["web_socket"] = web_socket
|
request.variables["web_socket"] = web_socket
|
||||||
request.variables["client_id"] = client
|
request.variables["client_id"] = client
|
||||||
@ -126,6 +122,6 @@ class WebSocketServersManager:
|
|||||||
|
|
||||||
self.anp.controllers.execute(
|
self.anp.controllers.execute(
|
||||||
data["controller"],
|
data["controller"],
|
||||||
data["method"],
|
data["action"],
|
||||||
request
|
request
|
||||||
)
|
)
|
||||||
@ -1,8 +1,9 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from typing import Any, Self, Sequence
|
from typing import Any, Self
|
||||||
from re import Pattern as REPattern
|
from re import Pattern as REPattern
|
||||||
|
from json import loads as json_decode
|
||||||
from Utils.Patterns import RE
|
from Utils.Patterns import RE
|
||||||
|
|
||||||
class Check:
|
class Check:
|
||||||
@ -11,6 +12,10 @@ class Check:
|
|||||||
def is_string(item:Any|None) -> bool:
|
def is_string(item:Any|None) -> bool:
|
||||||
return isinstance(item, str)
|
return isinstance(item, str)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_binary(item:Any|None) -> bool:
|
||||||
|
return isinstance(item, bytes)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_key(cls:type[Self], item:Any|None) -> bool:
|
def is_key(cls:type[Self], item:Any|None) -> bool:
|
||||||
return isinstance(item, str) and RE.KEY.match(item) is not None
|
return isinstance(item, str) and RE.KEY.match(item) is not None
|
||||||
@ -38,3 +43,17 @@ class Check:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def is_regular_expression(item:Any|None) -> bool:
|
def is_regular_expression(item:Any|None) -> bool:
|
||||||
return isinstance(item, REPattern)
|
return isinstance(item, REPattern)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_json_data(item:Any|None, full:bool = False) -> bool:
|
||||||
|
if Check.is_dictionary(item) or Check.is_array(item):
|
||||||
|
return True
|
||||||
|
if Check.is_string(item) and len(item = item.strip()) >= 2 and item[0] + item[-1] in ("{}", "[]"):
|
||||||
|
if not full:
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
if json_decode(item) is not None:
|
||||||
|
return True
|
||||||
|
except Exception as _:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
@ -105,7 +105,7 @@ class Common:
|
|||||||
key:str
|
key:str
|
||||||
value:Any|None
|
value:Any|None
|
||||||
|
|
||||||
for key, value in cls.get_dictionaries(subinputs).items():
|
for key, value in cls.get_dictionary(subinputs).items():
|
||||||
if overwrite or key not in dictionary:
|
if overwrite or key not in dictionary:
|
||||||
dictionary[key] = value
|
dictionary[key] = value
|
||||||
|
|
||||||
@ -286,7 +286,13 @@ class Common:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def json_decode(data:str) -> dict[str, Any|None]|Sequence[Any|None]|None:
|
def json_decode(data:str|bytes) -> dict[str, Any|None]|Sequence[Any|None]|None:
|
||||||
|
if Check.is_binary(data):
|
||||||
|
for charset in ("utf-8", "latin1"):
|
||||||
|
try:
|
||||||
|
return json_decode(data.decode(charset))
|
||||||
|
except Exception as exception:
|
||||||
|
pass
|
||||||
try:
|
try:
|
||||||
return json_decode(data)
|
return json_decode(data)
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
@ -303,10 +309,11 @@ class Common:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def base64_decode(data:str) -> bytes|None:
|
def base64_decode(data:str) -> bytes|None:
|
||||||
try:
|
if Check.is_binary(data) or Check.is_string(data):
|
||||||
return base64_decode(data.encode("utf-8"))
|
try:
|
||||||
except Exception as exception:
|
return base64_decode(data)
|
||||||
pass
|
except Exception as exception:
|
||||||
|
pass
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@ -319,9 +326,11 @@ class Common:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def data_decode(cls:type[Self], data:str) -> Any|None:
|
def data_decode(cls:type[Self], data:str) -> Any|None:
|
||||||
if Check.is_string(data):
|
if Check.is_string(data) or Check.is_binary(data):
|
||||||
data = cls.base64_decode(data)
|
|
||||||
if Check.is_string(data):
|
if Check.is_string(data):
|
||||||
|
data = data.encode("latin1").decode("utf-8")
|
||||||
|
data = cls.base64_decode(data)
|
||||||
|
if Check.is_string(data) or Check.is_binary(data):
|
||||||
try:
|
try:
|
||||||
return cls.json_decode(data)
|
return cls.json_decode(data)
|
||||||
except Exception as exception:
|
except Exception as exception:
|
||||||
@ -333,8 +342,8 @@ class Common:
|
|||||||
if Check.is_function(callback):
|
if Check.is_function(callback):
|
||||||
try:
|
try:
|
||||||
return callback(*arguments)
|
return callback(*arguments)
|
||||||
except Exception as _:
|
except Exception as exception:
|
||||||
pass
|
print(exception)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user