Update drive.
This commit is contained in:
parent
c5c160baae
commit
7b32a7eba4
Makefile
src/snek
2
Makefile
2
Makefile
@ -15,7 +15,7 @@ run:
|
|||||||
$(GUNICORN) -w $(GUNICORN_WORKERS) -k aiohttp.worker.GunicornWebWorker snek.gunicorn:app --bind 0.0.0.0:$(PORT) --reload
|
$(GUNICORN) -w $(GUNICORN_WORKERS) -k aiohttp.worker.GunicornWebWorker snek.gunicorn:app --bind 0.0.0.0:$(PORT) --reload
|
||||||
|
|
||||||
install:
|
install:
|
||||||
python3 -m venv .venv
|
python3.12 -m venv .venv
|
||||||
$(PIP) install -e .
|
$(PIP) install -e .
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ from snek.view.search_user import SearchUserView
|
|||||||
from snek.view.avatar import AvatarView
|
from snek.view.avatar import AvatarView
|
||||||
from snek.system.profiler import profiler_handler
|
from snek.system.profiler import profiler_handler
|
||||||
from snek.view.terminal import TerminalView, TerminalSocketView
|
from snek.view.terminal import TerminalView, TerminalSocketView
|
||||||
|
from snek.view.drive import DriveView
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
SESSION_KEY = b"c79a0c5fda4b424189c427d28c9f7c34"
|
SESSION_KEY = b"c79a0c5fda4b424189c427d28c9f7c34"
|
||||||
|
|
||||||
@ -67,6 +68,13 @@ class Application(BaseApplication):
|
|||||||
self.jinja2_env.add_extension(EmojiExtension)
|
self.jinja2_env.add_extension(EmojiExtension)
|
||||||
|
|
||||||
self.setup_router()
|
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 journal_mode=WAL")
|
||||||
self.db.query("PRAGMA syncnorm=off")
|
self.db.query("PRAGMA syncnorm=off")
|
||||||
|
|
||||||
@ -79,10 +87,8 @@ class Application(BaseApplication):
|
|||||||
self.db["channel_message"].create_index(["channel_uid","user_uid"])
|
self.db["channel_message"].create_index(["channel_uid","user_uid"])
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.cache = Cache(self)
|
await app.services.drive.prepare_all()
|
||||||
self.services = get_services(app=self)
|
|
||||||
self.mappers = get_mappers(app=self)
|
|
||||||
|
|
||||||
def setup_router(self):
|
def setup_router(self):
|
||||||
self.router.add_get("/", IndexView)
|
self.router.add_get("/", IndexView)
|
||||||
@ -117,6 +123,8 @@ class Application(BaseApplication):
|
|||||||
self.router.add_view("/threads.html", ThreadsView)
|
self.router.add_view("/threads.html", ThreadsView)
|
||||||
self.router.add_view("/terminal.ws", TerminalSocketView)
|
self.router.add_view("/terminal.ws", TerminalSocketView)
|
||||||
self.router.add_view("/terminal.html", TerminalView)
|
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(
|
self.add_subapp(
|
||||||
"/docs",
|
"/docs",
|
||||||
|
@ -4,4 +4,10 @@ from snek.system.model import BaseModel,ModelField
|
|||||||
class DriveModel(BaseModel):
|
class DriveModel(BaseModel):
|
||||||
|
|
||||||
user_uid = ModelField(name="user_uid", required=True)
|
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
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from snek.system.model import BaseModel,ModelField
|
from snek.system.model import BaseModel,ModelField
|
||||||
|
import mimetypes
|
||||||
|
|
||||||
class DriveItemModel(BaseModel):
|
class DriveItemModel(BaseModel):
|
||||||
drive_uid = ModelField(name="drive_uid", required=True,kind=str)
|
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)
|
path = ModelField(name="path", required=True,kind=str)
|
||||||
file_type = ModelField(name="file_type", required=True,kind=str)
|
file_type = ModelField(name="file_type", required=True,kind=str)
|
||||||
file_size = ModelField(name="file_size", required=True,kind=int)
|
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
|
||||||
|
@ -5,17 +5,75 @@ class DriveService(BaseService):
|
|||||||
|
|
||||||
mapper_name = "drive"
|
mapper_name = "drive"
|
||||||
|
|
||||||
async def get_by_user(self, user_uid):
|
EXTENSIONS_PICTURES = ["jpg","jpeg","png","gif","svg","webp","tiff"]
|
||||||
drives = []
|
EXTENSIONS_VIDEOS = ["mp4","m4v","mov","wmv","webm","mkv","mpg","mpeg","avi","ogv","ogg","flv","3gp","3g2"]
|
||||||
async for model in self.find(user_uid=user_uid):
|
EXTENSIONS_ARCHIVES = ["zip","rar","7z","tar","tar.gz","tar.xz","tar.bz2","tar.lzma","tar.lz"]
|
||||||
drives.append(model)
|
EXTENSIONS_AUDIO = ["mp3","wav","ogg","flac","m4a","wma","aac","opus","aiff","au","mid","midi"]
|
||||||
return drives
|
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):
|
async def get_drive_name_by_extension(self, extension):
|
||||||
drives = await self.get_by_user(user_uid=user_uid)
|
if extension.startswith("."):
|
||||||
if len(drives) == 0:
|
extension = extension[1:]
|
||||||
model = await self.new()
|
if extension in self.EXTENSIONS_PICTURES:
|
||||||
model['user_uid'] = user_uid
|
return "Pictures"
|
||||||
await self.save(model)
|
if extension in self.EXTENSIONS_VIDEOS:
|
||||||
return model
|
return "Videos"
|
||||||
return drives[0]
|
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'])
|
||||||
|
@ -10,6 +10,7 @@ class DriveItemService(BaseService):
|
|||||||
model['drive_uid'] = drive_uid
|
model['drive_uid'] = drive_uid
|
||||||
model['name'] = name
|
model['name'] = name
|
||||||
model['path'] = str(path)
|
model['path'] = str(path)
|
||||||
|
model['extension'] = str(name).split(".")[-1]
|
||||||
model['file_type'] = type_
|
model['file_type'] = type_
|
||||||
model['file_size'] = size
|
model['file_size'] = size
|
||||||
if await self.save(model):
|
if await self.save(model):
|
||||||
|
@ -13,20 +13,66 @@ commands = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TerminalSession:
|
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):
|
def __init__(self,command):
|
||||||
self.master, self.slave = pty.openpty()
|
self.master, self.slave = pty.openpty()
|
||||||
self.sockets =[]
|
self.sockets =[]
|
||||||
self.buffer = b''
|
self.buffer = b''
|
||||||
self.process = subprocess.Popen(
|
self.process = None
|
||||||
command.split(" "),
|
|
||||||
stdin=self.slave,
|
#self.process = subprocess.Popen(
|
||||||
stdout=self.slave,
|
# command.split(" "),
|
||||||
stderr=self.slave,
|
# stdin=self.slave,
|
||||||
bufsize=0,
|
# stdout=self.slave,
|
||||||
universal_newlines=True
|
# stderr=self.slave,
|
||||||
)
|
# bufsize=0,
|
||||||
|
# universal_newlines=True
|
||||||
|
#)
|
||||||
|
|
||||||
|
|
||||||
async def read_output(self, ws):
|
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()
|
loop = asyncio.get_event_loop()
|
||||||
self.sockets.append(ws)
|
self.sockets.append(ws)
|
||||||
if len(self.sockets) > 1:
|
if len(self.sockets) > 1:
|
||||||
@ -57,6 +103,7 @@ class TerminalSession:
|
|||||||
break
|
break
|
||||||
|
|
||||||
async def write_input(self, data):
|
async def write_input(self, data):
|
||||||
|
await self.ensure_process()
|
||||||
os.write(self.master, data.encode())
|
os.write(self.master, data.encode())
|
||||||
|
|
||||||
|
|
||||||
|
30
src/snek/view/drive.py
Normal file
30
src/snek/view/drive.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user