Compare commits

...

2 Commits

Author SHA1 Message Date
cb310967cd Update. 2025-06-09 06:47:50 +02:00
3e7cb9387c Update. 2025-06-09 06:46:43 +02:00
7 changed files with 157 additions and 6 deletions

View File

@ -1,11 +1,11 @@
import pathlib import pathlib
import shutil import shutil
import sqlite3 import sqlite3
import asyncio
import click import click
from aiohttp import web from aiohttp import web
from IPython import start_ipython from IPython import start_ipython
from snek.shell import Shell
from snek.app import Application from snek.app import Application
@ -14,6 +14,15 @@ def cli():
pass pass
@cli.command()
def maintenance():
async def run():
app = Application(db_path="sqlite:///snek.db")
await app.services.container.maintenance()
await app.services.channel_message.maintenance()
asyncio.run(run())
@cli.command() @cli.command()
@click.option( @click.option(
"--db_path", default="snek.db", help="Database to initialize if not exists." "--db_path", default="snek.db", help="Database to initialize if not exists."
@ -68,9 +77,7 @@ def serve(port, host, db_path):
help="Database path for the application", help="Database path for the application",
) )
def shell(db_path): def shell(db_path):
app = Application(db_path=f"sqlite:///{db_path}") Shell(db_path).run()
start_ipython(argv=[], user_ns={"app": app})
def main(): def main():
cli() cli()

View File

@ -17,7 +17,7 @@ from snek.service.user import UserService
from snek.service.user_property import UserPropertyService from snek.service.user_property import UserPropertyService
from snek.service.util import UtilService from snek.service.util import UtilService
from snek.system.object import Object from snek.system.object import Object
from snek.service.statistics import StatisticsService
@functools.cache @functools.cache
def get_services(app): def get_services(app):
@ -39,6 +39,7 @@ def get_services(app):
"channel_attachment": ChannelAttachmentService(app=app), "channel_attachment": ChannelAttachmentService(app=app),
"container": ContainerService(app=app), "container": ContainerService(app=app),
"push": PushService(app=app), "push": PushService(app=app),
"statistics": StatisticsService(app=app),
} }
) )

View File

@ -5,6 +5,23 @@ from snek.system.template import whitelist_attributes
class ChannelMessageService(BaseService): class ChannelMessageService(BaseService):
mapper_name = "channel_message" mapper_name = "channel_message"
async def maintenance(self):
async for message in self.find():
updated_at = message["updated_at"]
html = message["html"]
await self.save(message)
self.mapper.db['channel_message'].upsert(
{
"uid": message["uid"],
"updated_at": updated_at,
},
["uid"],
)
if html != message["html"]:
print("Reredefined message", message["uid"])
async def create(self, channel_uid, user_uid, message, is_final=True): async def create(self, channel_uid, user_uid, message, is_final=True):
model = await self.new() model = await self.new()

View File

@ -43,6 +43,14 @@ class ContainerService(BaseService):
async def start(self, channel_uid): async def start(self, channel_uid):
return await self.compose.start(await self.get_container_name(channel_uid)) return await self.compose.start(await self.get_container_name(channel_uid))
async def maintenance(self):
async for channel in self.services.channel.find():
if not await self.get(channel["uid"]):
print("Creating container for channel", channel["uid"])
result = await self.create(channel_uid=channel["uid"])
print(result)
async def get_status(self, channel_uid): async def get_status(self, channel_uid):
return await self.compose.get_instance_status(await self.get_container_name(channel_uid)) return await self.compose.get_instance_status(await self.get_container_name(channel_uid))
@ -60,6 +68,11 @@ class ContainerService(BaseService):
volumes=None, volumes=None,
): ):
name = await self.get_container_name(channel_uid) name = await self.get_container_name(channel_uid)
test = await self.compose.get_instance(name)
if test:
return test
self.compose.create_instance( self.compose.create_instance(
name, name,
image, image,
@ -74,6 +87,7 @@ class ContainerService(BaseService):
+ "/home/ubuntu" + "/home/ubuntu"
], ],
) )
return await self.compose.get_instance(name)
async def create2( async def create2(
self, id, name, status, resources=None, user_uid=None, path=None, readonly=False self, id, name, status, resources=None, user_uid=None, path=None, readonly=False

View File

@ -0,0 +1,91 @@
from snek.system.service import BaseService
import sqlite3
class StatisticsService(BaseService):
def database(self):
db_path = self.app.db_path.split("///")[-1]
print(db_path)
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
# Existing analysis code...
def get_table_columns(table_name):
cursor.execute(f"PRAGMA table_info({table_name})")
return cursor.fetchall()
tables = [
'http_access', 'user', 'channel', 'channel_member', 'broadcast',
'channel_message', 'notification', 'repository', 'test', 'drive',
'user_property', 'a', 'channel_attachment', 'push_registration'
]
for table in tables:
print(f"\n--- Statistics for table: {table} ---")
columns = get_table_columns(table)
cursor.execute(f"SELECT COUNT(*) FROM {table}")
total_rows = cursor.fetchone()[0]
print(f"Total rows: {total_rows}")
for col in columns:
cid, name, col_type, notnull, dflt_value, pk = col
col_type_upper = col_type.upper()
cursor.execute(f"SELECT COUNT(DISTINCT '{name}') FROM {table}")
distinct_count = cursor.fetchone()[0]
print(f"\nColumn: {name} ({col_type})")
print(f"Distinct values: {distinct_count}")
if 'INT' in col_type_upper or 'BIGINT' in col_type_upper or 'FLOAT' in col_type_upper:
cursor.execute(f"SELECT MIN('{name}'), MAX('{name}'), AVG('{name}') FROM {table} WHERE '{name}' IS NOT NULL")
min_val, max_val, avg_val = cursor.fetchone()
print(f"Min: {min_val}, Max: {max_val}, Avg: {avg_val}")
elif 'TEXT' in col_type_upper and ('date' in name.lower() or 'time' in name.lower() or 'created' in name.lower() or 'updated' in name.lower() or 'on' in name.lower()):
cursor.execute(f"SELECT MIN({name}), MAX({name}) FROM {table} WHERE {name} IS NOT NULL")
min_date, max_date = cursor.fetchone()
print(f"Earliest: {min_date}, Latest: {max_date}")
elif 'TEXT' in col_type_upper:
cursor.execute(f"SELECT LENGTH({name}) FROM {table} WHERE {name} IS NOT NULL")
lengths = [len_row[0] for len_row in cursor.fetchall()]
if lengths:
avg_length = sum(lengths) / len(lengths)
max_length = max(lengths)
min_length = min(lengths)
print(f"Avg length: {avg_length:.2f}, Max length: {max_length}, Min length: {min_length}")
else:
print("No data to compute length statistics.")
# New statistics functions
def get_time_series_stats(table_name, date_column):
cursor.execute(f"SELECT strftime('%Y-%m-%d', {date_column}) AS day, COUNT(*) FROM {table_name} GROUP BY day")
return cursor.fetchall()
def get_count_created(table_name, date_column):
cursor.execute(f"SELECT COUNT(*) FROM {table_name}")
return cursor.fetchone()[0]
def get_channels_per_user():
cursor.execute("SELECT user_uid, COUNT(*) AS channel_count FROM channel_member GROUP BY user_uid ORDER BY channel_count DESC")
return cursor.fetchall()
def get_online_users():
cursor.execute("SELECT COUNT(*) FROM user WHERE last_ping >= datetime('now', '-5 minutes')")
return cursor.fetchone()[0]
# Example usage of new functions
messages_per_day = get_time_series_stats('channel_message', 'created_at')
users_created = get_count_created('user', 'created_at')
channels_created = get_count_created('channel', 'created_at')
channels_per_user = get_channels_per_user()
online_users = get_online_users()
# Print or store these stats as needed
print("\nMessages per day:", messages_per_day)
print("Total users created:", users_created)
print("Total channels created:", channels_created)
print("Channels per user (top):", channels_per_user[:10])
print("Currently online users:", online_users)
conn.close()

19
src/snek/shell.py Normal file
View File

@ -0,0 +1,19 @@
from snek.app import Application
from IPython import start_ipython
class Shell:
def __init__(self,db_path):
self.app = Application(db_path=f"sqlite:///{db_path}")
async def maintenance(self):
await self.app.services.container.maintenance()
await self.app.services.channel_message.maintenance()
def run(self):
ns = {
"app": self.app,
"maintenance": self.maintenance
}
start_ipython(argv=[], user_ns=ns)

View File

@ -84,6 +84,8 @@ class ComposeFileManager:
async def get_instance(self, name): async def get_instance(self, name):
instance = self.compose.get("services", {}).get(name) instance = self.compose.get("services", {}).get(name)
if not instance:
return None
instance = json.loads(json.dumps(instance,default=str)) instance = json.loads(json.dumps(instance,default=str))
instance['status'] = await self.get_instance_status(name) instance['status'] = await self.get_instance_status(name)
return instance return instance