wip: Fix AI Interpreter. Doing Cookies and Sessions Manager.

This commit is contained in:
mbruzon 2026-06-08 14:47:31 +02:00
parent c73884ef35
commit b4a1d09e3d
23 changed files with 1080 additions and 566 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@
/Python/websockets /Python/websockets
__pycache__ __pycache__
.sass-cache .sass-cache
/Public/fonts/FontAwesome-6.7.2

View File

@ -6,6 +6,7 @@ import {SettingsManager} from "../Managers/SettingsManager.ecma.js";
import {I18NManager} from "../Managers/I18NManager.ecma.js"; import {I18NManager} from "../Managers/I18NManager.ecma.js";
import {ThreadsManager} from "../Managers/ThreadsManager.ecma.js"; import {ThreadsManager} from "../Managers/ThreadsManager.ecma.js";
import {UniqueKeysManager} from "../Managers/UniqueKeysManager.ecma.js"; import {UniqueKeysManager} from "../Managers/UniqueKeysManager.ecma.js";
import {CookiesManager} from "../Managers/CookiesManager.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 {ControllersManager} from "../Managers/ControllersManager.ecma.js";
@ -65,6 +66,8 @@ export const AnP = (function(){
this.threads = new ThreadsManager(self); this.threads = new ThreadsManager(self);
/** @type {UniqueKeysManager} */ /** @type {UniqueKeysManager} */
this.unique_keys = new UniqueKeysManager(self); this.unique_keys = new UniqueKeysManager(self);
/** @type {CookiesManager} */
this.cookies = new CookiesManager(self);
/** @type {SessionsManager} */ /** @type {SessionsManager} */
this.sessions = new SessionsManager(self); this.sessions = new SessionsManager(self);
/** @type {ModelsManager} */ /** @type {ModelsManager} */

View File

@ -65,7 +65,7 @@ export const AIChatComponent = (function(){
data_name : name, data_name : name,
data_i18n : value, data_i18n : value,
data_i18n_without : true, data_i18n_without : true,
title : anp.components.i18n(value) title : anp.i18n.get(value)
}, [ }, [
anp.components.icon(value), anp.components.icon(value),
anp.components.i18n(value) anp.components.i18n(value)
@ -75,7 +75,7 @@ export const AIChatComponent = (function(){
data_name : name, data_name : name,
data_i18n : name, data_i18n : name,
data_i18n_without : true, data_i18n_without : true,
title : anp.components.i18n(name) title : anp.i18n.get(name)
}, [ }, [
anp.components.icon(name), anp.components.icon(name),
anp.components.i18n(name), anp.components.i18n(name),
@ -174,6 +174,7 @@ export const AIChatComponent = (function(){
}; };
this.write_response = (id, fragment, ok, done) => { this.write_response = (id, fragment, ok, done) => {
console.log([id, fragment]);
const box = document.querySelector(".aichat .messages>[data-type=bot][data-id='" + id + "']"), const box = document.querySelector(".aichat .messages>[data-type=bot][data-id='" + id + "']"),
status = ( status = (
@ -185,17 +186,20 @@ export const AIChatComponent = (function(){
status_i18n_box = status_box.querySelector("[data-i18n]"), status_i18n_box = status_box.querySelector("[data-i18n]"),
date = Date.now(), date = Date.now(),
tokens_box = box.querySelector("[data-name=response_tokens] .value"), tokens_box = box.querySelector("[data-name=response_tokens] .value"),
[html, raw_html, md] = format(box.querySelector(".md-content").innerText += fragment); [html, raw_html, md] = format(box.querySelector(".md-content").textContent += fragment);
box.querySelector(".html-content").innerHTML = html; box.querySelector(".html-content").innerHTML = html;
box.querySelector(".raw-html-content").innerHTML = raw_html; box.querySelector(".raw-html-content").innerHTML = raw_html;
box.querySelector("[data-name=length] .value").innerText = md.length;
box.setAttribute("data-ok", ok); box.setAttribute("data-ok", ok);
box.setAttribute("data-done", done); box.setAttribute("data-done", done);
box.setAttribute("data-status", status); box.setAttribute("data-status", status);
status_box.setAttribute("data-i18n", status); status_box.setAttribute("data-i18n", status);
status_box.setAttribute("title", status_text); status_box.setAttribute("title", status_text);
status_box.querySelector("[data-icon]").setAttribute("data-icon", status);
status_i18n_box.setAttribute("data-i18n", status_text); status_i18n_box.setAttribute("data-i18n", status_text);
status_i18n_box.innerHTML = status_text; status_i18n_box.innerHTML = status_text;

View File

@ -0,0 +1,107 @@
"use strict";
import {Check} from "../Utils/Check.ecma.js";
import {Common} from "../Utils/Common.ecma.js";
/**
* @typedef {import("../Application/AnP.ecma.js").AnP} AnP
*/
/**
* @class CookiesManager
* @constructor
* @param {!AnP} anp
* @return {void}
* @access public
* @static
*/
export const CookiesManager = (function(){
/**
* @constructs CookiesManager
* @param {!AnP} anp
* @return {void}
* @access private
* @static
*/
const CookiesManager = function(anp){
/** @type {CookiesManager} */
const self = this;
/**
* @returns {void}
* @access private
*/
const constructor = () => {};
/**
* @returns {Object.<string, Any|null>}
* @access public
*/
this.to_dictionary = () => document.cookie.split(";").map(cookie => cookie.trim().split("=")).reduce((dictionary, [key, value]) => {
dictionary[key] = value;
return dictionary;
}, {});
/**
*
* @param {!string} name
* @param {any|null} value
* @param {!(boolean|Object.<string, Any|null>|Array.<any|null>)} options
* @returns
*/
this.set = (name, value, options = {}) => {
if(Common.get_value("overwrite", (
Check.is_boolean ? {overwrite : options} :
options), false) || !self.has(name)){
document.cookie = (
`${name}=${value}` +
(Common.get_value("expires", options) ? `; expires=${options.expires.toUTCString()}` : "") +
(Common.get_value("path", options) ? `; path=${options.path}` : "") +
(Common.get_value("domain", options) ? `; domain=${options.domain}` : "") +
(Common.get_value("secure", options) ? `; secure` : "")
);
return true;
};
return false;
};
/**
* @param {!string} name
* @returns {boolean}
* @access public
*/
this.has = name => name in self.to_dictionary();
/**
* @param {!string} name
* @returns {string|null}
* @access public
*/
this.get = name => self.to_dictionary()[name] || null;
/**
* @param {!string} name
* @param {!(boolean|Object.<string, any|null>|Array.<any|null>)} options
* @returns {boolean}
* @access public
*/
this.delete = (name, options = {}) => {
if(self.has(name)){
self.set(name, "", {
expires : new Date(0),
...Common.get_dictionary(options)
});
return true;
};
return false;
};
constructor();
};
return CookiesManager;
})();

View File

@ -18,9 +18,7 @@
<meta name="xdoc:author" content="KyMAN" /> <meta name="xdoc:author" content="KyMAN" />
<meta name="xdoc:access" content="public" /> <meta name="xdoc:access" content="public" />
<style type="text/css" data-type="text/css;charset=utf-8" data-css-map="/scss/AnP.css.map" data-scss="/scss/AnP.scss" data-crossorigin="anonymous" charset="utf-8"> <style type="text/css" data-type="text/css;charset=utf-8" data-crossorigin="anonymous" charset="utf-8">
@import url("/scss/AnP.css");
html,body{ html,body{
height : 100%; height : 100%;
@ -30,6 +28,8 @@
</style> </style>
<link type="text/css;charset=utf-8" data-language="SASS/CSS3" rel="stylesheet" href="/scss/AnP.css" data-css-map="/scss/AnP.css.map" data-scss="/scss/AnP.scss" charset="utf-8" crossorigin="anonymous" />
<script type="module" data-type="text/javascript;charset=utf-8" data-language="ECMAScript 2015" charset="utf-8"> <script type="module" data-type="text/javascript;charset=utf-8" data-language="ECMAScript 2015" charset="utf-8">
"use strict"; "use strict";

View File

@ -1,19 +0,0 @@
// @use "sass:map";
// @use "sass:list";
// @use "sass:meta";
@function unicode($code){
@return unquote("\"") + unquote(str-insert($code, "\\", 1)) + unquote("\"");
}
@function map-deep-get($scope, $keys...){
$i : 1;
@while (type-of($scope) == map) and ($i <= length($keys)){
$scope : map-get($scope, nth($keys, $i));
$i : $i + 1;
}
@return $scope;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,23 +0,0 @@
.anp{
[data-icon]::before{
margin-right : .3em;
font-family : $font-icon;
}
[data-icon=home]::before{content : unicode("f015");}
[data-icon=git]::before{content : unicode("f841"); font-family : "FA6FB";}
[data-icon=user]::before{content : unicode("f007");}
[data-icon=ip]::before{content : "IP"; font-weight : 900; font-family : $font-normal;}
[data-icon=login]::before{content : unicode("f090");}
[data-icon=register]::before{content : unicode("f234");}
[data-icon=logout]::before{content : unicode("f08b");}
[data-icon=zoom]::before{content : unicode("f002");}
[data-icon=reset_zoom]::before{content : unicode("f689");}
[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");}
}

View File

@ -1 +1,6 @@
@import "AnP.fonts.scss", "AnP.settings.scss", "AnP.common.scss", "AnP.base.scss", "AnP.icons.scss", "AnP.aichat.scss"; @use "fonts";
@use "settings";
@use "common";
@use "base";
@use "icons";
@use "aichat";

View File

@ -1,14 +1,17 @@
@use "settings" as *;
@use "common" as *;
@mixin aichar-color($mode){ @mixin aichar-color($mode){
.aichat>legend{border-bottom-color : map-deep-get($color, $mode, "fore")} .aichat>legend{border-bottom-color : map-deep-get($color, $mode, "fore")}
} }
.anp{ .anp{
&[data-forced-gui-mode=default][data-gui-mode=default]{ &[data-forced-gui-mode=default][data-gui-mode=default]{
@include main_color_web(light); @include aichar-color(light);
} }
@each $key in (dark, light){ @each $key in (dark, light){
&[data-forced-gui-mode=#{$key}],&[data-forced-gui-mode=default][data-gui-mode=#{$key}]{ &[data-forced-gui-mode=#{$key}],&[data-forced-gui-mode=default][data-gui-mode=#{$key}]{
@include main_color_web($key); @include aichar-color($key);
} }
} }

View File

@ -1,3 +1,6 @@
@use "settings" as *;
@use "common" as *;
@mixin main_color_web($mode){ @mixin main_color_web($mode){
background-color : map-deep-get($color, $mode, "back"); background-color : map-deep-get($color, $mode, "back");
color : map-deep-get($color, $mode, "fore"); color : map-deep-get($color, $mode, "fore");
@ -13,6 +16,7 @@
box-shadow : 0em 0em .2em inset map-deep-get($color, $mode, "secondary"); box-shadow : 0em 0em .2em inset map-deep-get($color, $mode, "secondary");
} }
} }
.i18n-selector li{background-color : map-deep-get($color, $mode, "back");}
} }
.anp{ .anp{

20
Public/scss/_common.scss Normal file
View File

@ -0,0 +1,20 @@
@use "sass:map";
@use "sass:list";
@use "sass:meta";
@use "sass:string";
@function unicode($code){
@return string.unquote("\"") + string.unquote(string.insert($code, "\\", 1)) + string.unquote("\"");
}
@function map-deep-get($scope, $keys...){
$i : 1;
@while (meta.type-of($scope) == map) and ($i <= list.length($keys)){
$scope : map.get($scope, list.nth($keys, $i));
$i : $i + 1;
}
@return $scope;
}

View File

@ -1,3 +1,59 @@
// @font-face {
// font-family : "Font Awesome 6 Brands";
// font-style : normal;
// font-weight : 400;
// font-display : block;
// src :
// url("/fonts/FontAwesome-6.7.2/fa-brands-400.woff2") format("woff2"),
// url("/fonts/FontAwesome-6.7.2/fa-brands-400.ttf") format("truetype");
// }
// @font-face {
// font-family : "Font Awesome 6 Regular";
// font-style : normal;
// font-weight : 400;
// font-display : block;
// src :
// url("/fonts/FontAwesome-6.7.2/fa-regular-400.woff2") format("woff2"),
// url("/fonts/FontAwesome-6.7.2/fa-regular-400.ttf") format("truetype");
// }
// @font-face {
// font-family : "Font Awesome 6 Solid";
// font-style : normal;
// font-weight : 900;
// font-display : block;
// src :
// url("/fonts/FontAwesome-6.7.2/fa-solid-900.woff2") format("woff2"),
// url("/fonts/FontAwesome-6.7.2/fa-solid-900.ttf") format("truetype");
// }
// @font-face {
// font-family : "FA6FB";
// font-style : normal;
// font-weight : 400;
// font-display : block;
// src :
// url("/fonts/FontAwesome-6.7.2/fa-brands-400.woff2") format("woff2"),
// url("/fonts/FontAwesome-6.7.2/fa-brands-400.ttf") format("truetype");
// }
// @font-face {
// font-family : "FA6FR";
// font-style : normal;
// font-weight : 400;
// font-display : block;
// src :
// url("/fonts/FontAwesome-6.7.2/fa-regular-400.woff2") format("woff2"),
// url("/fonts/FontAwesome-6.7.2/fa-regular-400.ttf") format("truetype");
// }
// @font-face {
// font-family : "FA6FS";
// font-style : normal;
// font-weight : 900;
// font-display : block;
// src :
// url("/fonts/FontAwesome-6.7.2/fa-solid-900.woff2") format("woff2"),
// url("/fonts/FontAwesome-6.7.2/fa-solid-900.ttf") format("truetype");
// }
@font-face { @font-face {
font-family : "FA6FB"; font-family : "FA6FB";
font-style : normal; font-style : normal;
@ -26,6 +82,42 @@
url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-solid-900.ttf") format("truetype"); url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/webfonts/fa-solid-900.ttf") format("truetype");
} }
// @font-face {
// font-family : "FA6FB";
// font-style : normal;
// font-weight : 400;
// font-display : block;
// src :
// url("https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.7.2/webfonts/fa-brands-400.woff2") format("woff2"),
// url("https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.7.2/webfonts/fa-brands-400.ttf") format("truetype");
// }
// @font-face {
// font-family : "FA6FR";
// font-style : normal;
// font-weight : 400;
// font-display : block;
// src :
// url("https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.7.2/webfonts/fa-regular-400.woff2") format("woff2"),
// url("https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.7.2/webfonts/fa-regular-400.ttf") format("truetype");
// }
// @font-face {
// font-family : "FA6FS";
// font-style : normal;
// font-weight : 900;
// font-display : block;
// src :
// url("https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.7.2/webfonts/fa-solid-900.woff2") format("woff2"),
// url("https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.7.2/webfonts/fa-solid-900.ttf") format("truetype");
// }
$FA6FB : "FA6FB";
$FA6FR : "FA6FR";
$FA6FS : "FA6FS";
// $FA6FB : "Font Awesome 6 Brands";
// $FA6FR : "Font Awesome 6 Regular";
// $FA6FS : "Font Awesome 6 Solid";
/* cyrillic-ext */ /* cyrillic-ext */
@font-face{ @font-face{
font-family : "Roboto"; font-family : "Roboto";

40
Public/scss/_icons.scss Normal file
View File

@ -0,0 +1,40 @@
@use "settings" as *;
@use "fonts" as *;
@use "common" as *;
.anp{
[data-icon]::before{
margin-right : .3em;
font-family : $font-icon;
}
[data-icon=home]::before{content : unicode("f015");}
[data-icon=git]::before{content : unicode("f841"); font-family : $FA6FB;}
[data-icon=user]::before{content : unicode("f007");}
[data-icon=ip]::before{content : "IP"; font-weight : 900; font-family : $font-normal;}
[data-icon=login]::before{content : unicode("f090");}
[data-icon=register]::before{content : unicode("f234");}
[data-icon=logout]::before{content : unicode("f08b");}
[data-icon=zoom]::before{content : unicode("f002");}
[data-icon=reset_zoom]::before{content : unicode("f689");}
[data-icon=gui_mode]::before{content : unicode("f043");}
[data-icon=send]::before{content : unicode("f1d8"); font-family : $FA6FR;}
// 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");}
[data-icon=done]::before{content : unicode("f164"); font-family : $FA6FR;}
[data-icon=think]::before{content : unicode("f731"); font-family : $FA6FB;}
[data-icon=loading]::before{content : unicode("f110");}
[data-icon=waiting]::before{content : unicode("f252");}
[data-ok=true] [data-icon=ok]::before{content : unicode("f00c");}
[data-ok=false] [data-icon=ok]::before{content : unicode("f00d");}
[data-done=true] [data-icon=done]::before{content : unicode("f058"); font-family : $FA6FR;}
[data-done=false] [data-icon=done]::before{content : unicode("f071");}
[data-icon=date_from]::before{content : unicode("f783");}
[data-icon=date_to]::before{content : unicode("f1da");}
[data-icon=time]::before{content : unicode("f017"); font-family : $FA6FR;}
[data-icon=length]::before{content : unicode("f546");}
[data-icon=response_tokens]::before{content : unicode("f4ad"); font-family : $FA6FR;}
}

View File

@ -1,3 +1,6 @@
@use "sass:color";
@use "fonts" as *;
// Colors // Colors
$color-fore : #222; $color-fore : #222;
$color-back : #EFEFEF; $color-back : #EFEFEF;
@ -5,24 +8,24 @@ $color-primary : #2272D4;
$color-secondary : #D47222; $color-secondary : #D47222;
$color-full-fore : #000; $color-full-fore : #000;
$color-full-back : #FFF; $color-full-back : #FFF;
$color-grey : mix($color-fore, $color-back, 50%); $color-grey : color.mix($color-fore, $color-back, 50%);
$color : ( $color : (
light : ( light : (
fore : $color-fore, fore : $color-fore,
back : $color-back, back : $color-back,
primary : mix($color-primary, $color-fore, 80%), primary : color.mix($color-primary, $color-fore, 80%),
secondary : mix($color-secondary, $color-fore, 80%), secondary : color.mix($color-secondary, $color-fore, 80%),
full : $color-full-back, full : $color-full-back,
input-back : mix($color-back, $color-full-back, 80%), input-back : color.mix($color-back, $color-full-back, 80%),
transparent : rgba(255, 255, 255, 0) transparent : rgba(255, 255, 255, 0)
), ),
dark : ( dark : (
fore : $color-back, fore : $color-back,
back : $color-fore, back : $color-fore,
primary : mix($color-primary, $color-back, 80%), primary : color.mix($color-primary, $color-back, 80%),
secondary : mix($color-secondary, $color-back, 80%), secondary : color.mix($color-secondary, $color-back, 80%),
full : $color-full-fore, full : $color-full-fore,
input-back : mix($color-back, $color-full-fore, 80%), input-back : color.mix($color-back, $color-full-fore, 80%),
transparent : rgba(0, 0, 0, 0) transparent : rgba(0, 0, 0, 0)
) )
); );
@ -39,7 +42,7 @@ $margin : .5em;
// $font-icon : Arial, Helvetica, Sans; // $font-icon : Arial, Helvetica, Sans;
$font-normal : "Roboto"; $font-normal : "Roboto";
$font-mono : "Roboto Mono"; $font-mono : "Roboto Mono";
$font-icon : "FA6FS"; $font-icon : $FA6FS;
// Transitions // Transitions
$transition-in : .35s; $transition-in : .35s;

View File

@ -39,9 +39,12 @@ class AIController(ControllerAbstract, ModelAbstract):
}) })
def __message_execution(self:Self, end:Callable[[], None], request:RequestModel) -> None: def __message_execution(self:Self, end:Callable[[], None], request:RequestModel) -> None:
self.anp.ai_interpreters.request(
session:str|None = None
session, _ = self.anp.ai_interpreters.request(
"anp_responses", "anp_responses",
None, session,
request.get("message"), request.get("message"),
lambda id, response: self.anp.web_socket_servers.send("anp", "ai", "message", { lambda id, response: self.anp.web_socket_servers.send("anp", "ai", "message", {
"id" : id, "id" : id,
@ -51,6 +54,7 @@ class AIController(ControllerAbstract, ModelAbstract):
"data_id" : request.get("message_id") "data_id" : request.get("message_id")
}, request.get("client_id")) }, request.get("client_id"))
) )
end() end()
def message(self:Self, request:RequestModel) -> None: def message(self:Self, request:RequestModel) -> None:

View File

@ -1,11 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from typing import Self, Optional from typing import Self, Optional, Any
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from Models.SessionModel import SessionModel
class SessionsManagerInterface(ABC): class SessionsManagerInterfaces(ABC):
@abstractmethod @abstractmethod
def update(self:Self) -> None:pass def update(self:Self) -> None:pass
@ -14,7 +13,10 @@ class SessionsManagerInterface(ABC):
def reset(self:Self) -> None:pass def reset(self:Self) -> None:pass
@abstractmethod @abstractmethod
def get(self:Self, id:Optional[str] = None) -> SessionModel|None:pass def get(self:Self, id:str, key:str, default:Optional[Any] = None) -> Any|None:pass
@abstractmethod
def set(self:Self, id:str, key:str, value:Any|None) -> bool:pass
@abstractmethod @abstractmethod
def remove(self:Self, id:str) -> bool:pass def remove(self:Self, id:str) -> bool:pass

View File

@ -1,7 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from typing import Self, Optional from typing import Self, Optional, Any
from threading import Thread
from time import sleep, time as timestamp
from Interfaces.Application.AnPInterface import AnPInterface from Interfaces.Application.AnPInterface import AnPInterface
from Models.SessionModel import SessionModel from Models.SessionModel import SessionModel
@ -11,8 +13,12 @@ class SessionsManager:
self.anp:AnPInterface = anp self.anp:AnPInterface = anp
self.__sessions:dict[str, SessionModel] = {} self.__sessions:dict[str, SessionModel] = {}
self.__thread:Thread = Thread(target = self.__autoclean)
self.__timeout:float|int = self.anp.settings.get(("sessions_timeout", "timeout"), None, 3600)
self.__clean_waiter:float|int = self.anp.settings.get(("sessions_clean_waiter", "clean_waiter"), None, 60)
self.update() self.update()
self.__thread.start()
def update(self:Self) -> None:pass def update(self:Self) -> None:pass
@ -22,15 +28,29 @@ class SessionsManager:
self.update() self.update()
def get(self:Self, id:Optional[str] = None) -> SessionModel|None: def __autoclean(self:Self) -> None:
if id is None: while self.anp.working():
session:SessionModel = SessionModel(self.anp.unique_keys.get()) id:str
session:SessionModel
time:float = timestamp()
self.__sessions[session.id] = session for id, session in tuple(self.__sessions.items()):
if time - session.get("date_last", time) > self.__timeout:
self.remove(id)
return session sleep(self.__clean_waiter)
return self.__sessions.get(id, None)
def get(self:Self, id:str, key:str, default:Optional[Any] = None) -> Any|None:
if id in self.__sessions:
return self.__sessions[id].get(key, default)
return default
def set(self:Self, id:str, key:str, value:Any|None) -> bool:
if id in self.__sessions:
self.__sessions[id].set(key, value)
return True
return False
def remove(self:Self, id:str) -> bool: def remove(self:Self, id:str) -> bool:
if id in self.__sessions: if id in self.__sessions:

View File

@ -3,6 +3,7 @@
from typing import Any, Self, Callable, Sequence, Optional from typing import Any, Self, Callable, Sequence, Optional
from json import dumps as json_encode from json import dumps as json_encode
from Models.SessionModel import SessionModel
from Abstracts.RouteAbstract import RouteAbstract from Abstracts.RouteAbstract import RouteAbstract
from Utils.Common import Common from Utils.Common import Common
@ -22,11 +23,12 @@ class RequestModel:
self.response_headers:dict[str, Any|None] = {} self.response_headers:dict[str, Any|None] = {}
self.callback:Callable[[RequestModel, str|bytes|None], None]|None = None self.callback:Callable[[RequestModel, str|bytes|None], None]|None = None
self.data:Any|None = None self.data:Any|None = None
self.session:SessionModel|None = None
def get(self:Self, key:str|Sequence[str], default:Optional[Any] = None) -> Any|None: def get(self:Self, key:str|Sequence[str], default:Optional[Any] = None) -> Any|None:
return Common.get_value(key, ( return self.session.get(key, Common.get_value(key, (
self.url_variables, self.get_variables, self.post_variables, self.variables self.url_variables, self.get_variables, self.post_variables, self.variables
), default) ), default))
def set_variables(self:Self, inputs:dict[str, Any|None], on:Optional[str] = None) -> None: def set_variables(self:Self, inputs:dict[str, Any|None], on:Optional[str] = None) -> None:
( (

View File

@ -2,9 +2,20 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from typing import Self, Any from typing import Self, Any
from time import time as timestamp
class SessionModel: class SessionModel:
def __init__(self:Self, id:str) -> None: def __init__(self:Self, id:str) -> None:
self.id:str = id self.id:str = id
self.date_from:float = timestamp()
self.date_last:float = timestamp()
self.variables:dict[str, Any|None] = {} self.variables:dict[str, Any|None] = {}
def set(self:Self, key:str, value:Any|None) -> None:
self.date_last = timestamp()
self.variables[key] = value
def get(self:Self, key:str, default:Any|None = None) -> Any|None:
self.date_last = timestamp()
return self.variables.get(key, default)

View File

@ -258,6 +258,10 @@ class Common:
@staticmethod @staticmethod
def get_mime_from_path(path:str) -> str|None: def get_mime_from_path(path:str) -> str|None:
# if path[-6:] == ".woff2":
# return "font/woff2"
# if path[-4:] == ".ttf":
# return "font/ttf"
return get_mime_by_extension(path)[0] return get_mime_by_extension(path)[0]
@classmethod @classmethod

3
Tools/sass.win.bat Normal file
View File

@ -0,0 +1,3 @@
@echo off
cd %~dp0
sass ..\Public\scss\AnP.scss ..\Public\scss\AnP.css