Update drive.

This commit is contained in:
retoor 2025-03-23 13:57:20 +01:00
parent c5c160baae
commit 7b32a7eba4
8 changed files with 187 additions and 28 deletions

View File

@ -15,7 +15,7 @@ run:
$(GUNICORN) -w $(GUNICORN_WORKERS) -k aiohttp.worker.GunicornWebWorker snek.gunicorn:app --bind 0.0.0.0:$(PORT) --reload
install:
python3 -m venv .venv
python3.12 -m venv .venv
$(PIP) install -e .

View File

@ -38,6 +38,7 @@ from snek.view.search_user import SearchUserView
from snek.view.avatar import AvatarView
from snek.system.profiler import profiler_handler
from snek.view.terminal import TerminalView, TerminalSocketView
from snek.view.drive import DriveView
from concurrent.futures import ThreadPoolExecutor
SESSION_KEY = b"c79a0c5fda4b424189c427d28c9f7c34"
@ -67,6 +68,13 @@ class Application(BaseApplication):
self.jinja2_env.add_extension(EmojiExtension)
self.setup_router()
self.cache = Cache(self)
self.services = get_services(app=self)
self.mappers = get_mappers(app=self)
self.on_startup.append(self.prepare_database)
async def prepare_database(self,app):
self.db.query("PRAGMA journal_mode=WAL")
self.db.query("PRAGMA syncnorm=off")
@ -79,10 +87,8 @@ class Application(BaseApplication):
self.db["channel_message"].create_index(["channel_uid","user_uid"])
except:
pass
self.cache = Cache(self)
self.services = get_services(app=self)
self.mappers = get_mappers(app=self)
await app.services.drive.prepare_all()
def setup_router(self):
self.router.add_get("/", IndexView)
@ -117,6 +123,8 @@ class Application(BaseApplication):
self.router.add_view("/threads.html", ThreadsView)
self.router.add_view("/terminal.ws", TerminalSocketView)
self.router.add_view("/terminal.html", TerminalView)
self.router.add_view("/drive.json", DriveView)
self.router.add_view("/drive/{drive}.json", DriveView)
self.add_subapp(
"/docs",

View File

@ -4,4 +4,10 @@ from snek.system.model import BaseModel,ModelField
class DriveModel(BaseModel):
user_uid = ModelField(name="user_uid", required=True)
name = ModelField(name='name', required=False, type=str)
@property
async def items(self):
async for drive_item in self.app.services.drive_item.find(drive_uid=self['uid']):
yield drive_item

View File

@ -1,5 +1,5 @@
from snek.system.model import BaseModel,ModelField
import mimetypes
class DriveItemModel(BaseModel):
drive_uid = ModelField(name="drive_uid", required=True,kind=str)
@ -7,3 +7,12 @@ class DriveItemModel(BaseModel):
path = ModelField(name="path", required=True,kind=str)
file_type = ModelField(name="file_type", required=True,kind=str)
file_size = ModelField(name="file_size", required=True,kind=int)
@property
def extension(self):
return self['name'].split('.')[-1]
@property
def mime_type(self):
mimetype,_ = mimetypes.guess_type(self['name'])
return mimetype

View File

@ -5,17 +5,75 @@ class DriveService(BaseService):
mapper_name = "drive"
async def get_by_user(self, user_uid):
drives = []
async for model in self.find(user_uid=user_uid):
drives.append(model)
return drives
EXTENSIONS_PICTURES = ["jpg","jpeg","png","gif","svg","webp","tiff"]
EXTENSIONS_VIDEOS = ["mp4","m4v","mov","wmv","webm","mkv","mpg","mpeg","avi","ogv","ogg","flv","3gp","3g2"]
EXTENSIONS_ARCHIVES = ["zip","rar","7z","tar","tar.gz","tar.xz","tar.bz2","tar.lzma","tar.lz"]
EXTENSIONS_AUDIO = ["mp3","wav","ogg","flac","m4a","wma","aac","opus","aiff","au","mid","midi"]
EXTENSIONS_DOCS = ["pdf","doc","docx","xls","xlsx","ppt","pptx","txt","md","json","csv","xml","html","css","js","py","sql","rs","toml","yml","yaml","ini","conf","config","log","csv","tsv","java","cs","csproj","scss","less","sass","json","lock","lock.json","jsonl"]
async def get_or_create(self, user_uid):
drives = await self.get_by_user(user_uid=user_uid)
if len(drives) == 0:
model = await self.new()
model['user_uid'] = user_uid
await self.save(model)
return model
return drives[0]
async def get_drive_name_by_extension(self, extension):
if extension.startswith("."):
extension = extension[1:]
if extension in self.EXTENSIONS_PICTURES:
return "Pictures"
if extension in self.EXTENSIONS_VIDEOS:
return "Videos"
if extension in self.EXTENSIONS_ARCHIVES:
return "Archives"
if extension in self.EXTENSIONS_AUDIO:
return "Audio"
if extension in self.EXTENSIONS_DOCS:
return "Documents"
return "My Drive"
async def get_drive_by_extension(self,user_uid, extension):
name = await self.get_drive_name_by_extension(extension)
return await self.get_or_create(user_uid=user_uid,name=name)
async def get_by_user(self, user_uid,name=None):
kwargs = dict(
user_uid = user_uid
)
async for model in self.find(**kwargs):
if not name:
yield model
elif model['name'] == name:
yield model
elif not model['name'] and name == 'My Drive':
model['name'] = 'My Drive'
await self.save(model)
yield model
async def get_or_create(self, user_uid,name=None,extensions=None):
kwargs = dict(user_uid=user_uid)
if name:
kwargs['name'] = name
async for model in self.get_by_user(**kwargs):
return model
model = await self.new()
model['user_uid'] = user_uid
model['name'] = name
await self.save(model)
return model
async def prepare_default_drives(self):
async for drive_item in self.services.drive_item.find():
extension = drive_item.extension
drive = await self.get_drive_by_extension(drive_item['user_uid'],extension)
if not drive_item['drive_uid'] == drive['uid']:
drive_item['drive_uid'] = drive['uid']
await self.services.drive_item.save(drive_item)
async def prepare_default_drives_for_user(self, user_uid):
await self.get_or_create(user_uid=user_uid,name="My Drive")
await self.get_or_create(user_uid=user_uid,name="Shared Drive")
await self.get_or_create(user_uid=user_uid,name="Pictures")
await self.get_or_create(user_uid=user_uid,name="Videos")
await self.get_or_create(user_uid=user_uid,name="Archives")
await self.get_or_create(user_uid=user_uid,name="Documents")
async def prepare_all(self):
await self.prepare_default_drives()
async for user in self.services.user.find():
await self.prepare_default_drives_for_user(user['uid'])

View File

@ -10,6 +10,7 @@ class DriveItemService(BaseService):
model['drive_uid'] = drive_uid
model['name'] = name
model['path'] = str(path)
model['extension'] = str(name).split(".")[-1]
model['file_type'] = type_
model['file_size'] = size
if await self.save(model):

View File

@ -13,20 +13,66 @@ commands = {
}
class TerminalSession:
async def ensure_process(self):
if self.process:
return
self.process = await asyncio.create_subprocess_exec(
*self.command.split(" "),
stdin=self.slave,
stdout=self.slave,
stderr=self.slave,bufsize=0,
universal_newlines=True
)
def __init__(self,command):
self.master, self.slave = pty.openpty()
self.sockets =[]
self.buffer = b''
self.process = subprocess.Popen(
command.split(" "),
stdin=self.slave,
stdout=self.slave,
stderr=self.slave,
bufsize=0,
universal_newlines=True
)
self.process = None
#self.process = subprocess.Popen(
# command.split(" "),
# stdin=self.slave,
# stdout=self.slave,
# stderr=self.slave,
# bufsize=0,
# universal_newlines=True
#)
async def read_output(self, ws):
await self.ensure_process()
self.sockets.append(ws)
if len(self.sockets) > 1:
start = self.buffer.index(b'\n')
await ws.send_bytes(self.buffer[start:])
return
while True:
try:
async for data in self.process.stdout:
if not data:
break
self.buffer += data
if len(self.buffer) > 10000:
self.buffer = self.buffer[:-10000]
try:
for ws in self.sockets: await ws.send_bytes(data) # Send raw bytes for ANSI support
except:
self.sockets.remove(ws)
except:
print("Terminating process")
self.process.terminate()
print("Terminated process")
for ws in self.sockets:
try:
await ws.close()
except Exception:
pass
break
async def read_outputa(self, ws):
loop = asyncio.get_event_loop()
self.sockets.append(ws)
if len(self.sockets) > 1:
@ -57,6 +103,7 @@ class TerminalSession:
break
async def write_input(self, data):
await self.ensure_process()
os.write(self.master, data.encode())

30
src/snek/view/drive.py Normal file
View File

@ -0,0 +1,30 @@
from snek.system.view import BaseView
from aiohttp import web
class DriveView(BaseView):
login_required = True
async def get(self):
drive_uid = self.request.match_info.get("drive")
if drive_uid:
drive = await self.services.drive.get(uid=drive_uid)
drive_items = []
async for item in drive.items:
drive_items.append(item.record)
return web.json_response(drive_items)
user = await self.services.user.get(uid=self.session.get("uid"))
drives = []
async for drive in self.services.drive.get_by_user(user['uid']):
record = drive.record
record['items'] = []
async for item in drive.items:
record['items'].append(item.record)
drives.append(record)
return web.json_response(drives)