Как нам реорганизовать
РабКрин построить Продукт для
Zope.
Я тут потихоньку клепаю
загрузчик
мегафайлов, с блекджеком-и-шлюхами.
Чисто для себя, ибо периодически возникает
необходимость получить от контрагентов
нечто весомое, гигабайт в несколько.
Поскольку имеющиеся в доступе решения
меня не устраивают (основных претензий
две: течет память, поэтому мегафайлы
передать невозможно; докачки нет, либо
она зависит от клиентской части и поэтому
часто неосуществима на практике),
пришлось делать велосипед самому.
Интересно ведь :)
В предыдущий подход к
снаряду я доделал
версию
2, которая выполняет необходимый мне
минимум функций. Но, пока делал, пришел
к убеждению, что сделано все неправильно
:) Надо иначе.
Как иначе? А так. Поскольку
платформой я выбрал
Zope
(ну нравится оно мне), логично сделать
класс объектов, наподобие стандартного
типа «
File». Внешне новый
Файл будет отличаться от стандартного
только тем, что загружаться на сервер
он будет кусочками а не сразу. Ну и
храниться будет не в ZODB а в файловой
системе. Тема близкая к
(
http://old.zope.org/Members/shh/ExtFile/).
А чтобы сделать такой класс, надо
реализовать Продукт
(Product)
или, иначе, Аддон
(Add-on).
Поскольку это первый
в моей практике Продукт, попробую
задокументировать процесс. Надеюсь,
будет полезно не только мне, тем более,
что с качественной документацией для
Zope не все хорошо, мягко говоря.
Это было вступление,
если кто не догадался. Дальше пойдет
собственно материал. Детей, беременных
женщин и просто неуравновешенных прошу
удалиться из зала.
Исходные материалы
Что в активе, кроме
желания сделать Продукт.
Zope Version (Zope 2.11.4-final, python
2.4.4, win32)
c:\Zope\2.11.4\Zope\lib\python\Products\ZReST\
Заготовка
Для начала, следует
знать, что разработка аддонов через
ZClass-ы уже неактуальна.
Поэтому главу 23 Зопобука можно не читать.
Разрабатывать аддон надо построением
питонского пакета определенного формата.
Первым делом сделаю каркас, содержащий
необходимый минимум.
Кстати, при разработке
полезно запускать Zope в режиме дебага
(файл c:\Zope\Instance\2.11.4\etc\zope.conf, переключатель
debug-mode). Для запуска я сделал файл
debug.cmd с содержимым
@REM ~ # -*- mode: bat; coding: cp1251 -*-
@REM ~ # (c) Valik mailto:vasnake@gmail.com
@echo off
chcp 1251 > nul
set wd=%~dp0
pushd "%wd%"
set PYTHONPATH=
@rem предварительно надо остановить сервис, через ControlPanel ZMI к примеру
pushd c:\Zope\Instance\2.11.4\bin
start cmd.exe /c "c:\Zope\2.11.4\Python\python.exe zopeservice.py debug"
pause
|
Логи посмотреть можно
тут
c:\Zope\Instance\2.11.4\log\Z2.log
c:\Zope\Instance\2.11.4\log\event.log
Чуть отвлекся, вернемся
обратно к баранам.
Забегая вперед: это
описание не совсем точное, местами я
консультировался с разработчиками
других продуктов (ExtFile/ExtImage, ZReST и другие
из c:\Zope\2.11.4\Zope\lib\python\Products\), путем изучения
их кода.
Папка продукта должна
располагаться тут
c:\Zope\2.11.4\Zope\lib\python\Products\
или лучше тут
c:\Zope\Instance\2.11.4\Products\
Я назову тебя
стеклянным продукт «VCUFile», значит
папка продукта будет
c:\Zope\2.11.4\Zope\lib\python\Products\VCUFile
или, что лучше
c:\Zope\Instance\2.11.4\Products\VCUFile
Какие файлы и папки
следует включить в состав продукта:
vcufile.py – интерфейсы (соглашение такое, хотя можно и без них)
vcufileimpl.py – тестовая реализация интерфейсов, в продукте не нужен
vcufileproduct.py – реализация продукта
__init__.py – инициализация продукта
www – Contains your icon & ZPT files
help – Contains your help files
tests – Contains your unit tests
README.txt
VERSION.txt
LICENSE.txt
INSTALL.txt
TODO.txt
CHANGES.txt and HISTORY.txt
DEPENDENCIES.txt
|
Конечно, можно весь код
затолкать в __init__.py и
снабдить его одним readme.txt,
но лучше не надо. В процессе
эволюции джентльмены выработали
некоторые соглашения. Согласно этим
соглашениям, содержимое продукта следует
оформить как указано.
Приведу минимальное
содержимое этих файлов, содержимое,
которое формирует продукт, содержащий
один класс (VCUFile), объекты
которого можно добавлять в ZODB. Пока с
ними делать ничего нельзя, разве только
управлять доступом к объектам.
vcufile\vcufile.py
#!/usr/bin/env python
# -*- mode: python; coding: utf-8 -*-
# (c) Valik mailto:vasnake@gmail.com
# VCUFile public interfaces
# Фактически, этот модуль относится к документации
# и если бы его не было, работоспособности продукта это бы не помешало.
from zope.interface import Interface
class IVCUFile(Interface):
"""A giant file for chunked upload.
File will be stored in filesystem.
"""
def getFID():
"""File ID
Пример метода типа get.
Ну надо же было придумать хоть что нибудь.
"""
|
интерфейс следует
описать из соображений документированности
и установления «контракта». Людям так
удобнее.
vcufile\vcufileproduct.py
#!/usr/bin/env python
# -*- mode: python; coding: utf-8 -*-
# (c) Valik mailto:vasnake@gmail.com
__doc__ = """VCUFile product module.
The VCUFile Addon works like the Zope File product, but stores
the uploaded file externally and can upload giant files because of chunked upload."""
__version__ = '3.0.0.alpha'
from Acquisition import Implicit
from Globals import Persistent
from AccessControl.Role import RoleManager
from OFS.SimpleItem import Item
from AccessControl import ClassSecurityInfo
from Globals import InitializeClass
from vcufile import IVCUFile
from zope.interface import implements
def addForm(self):
"""Returns an HTML form for VCUFile 'add' action.
Constructor.
Эта функция вызывается, когда пользователь добавляет обьект
через список добавления в ZMI.
Сабмит формы вызывает addFunction (см.ниже).
"""
return """<html>
<head><title>Add VCUFile</title></head>
<body><form action="addFunction">
id <input type="type" name="id"><br>
filename <input type="type" name="filename"><br>
<input type="submit" value=" Add ">
</form></body>
</html>"""
#def addForm():
def addFunction(self, id, filename, REQUEST=None):
"""addForm processor function. Constructor.
Create a new VCUFile and add it to container.
Обработчик формы addForm, создает обьект и пишет его в контейнер.
"""
p = VCUFileProduct(id, filename)
self.Destination()._setObject(id, p)
if REQUEST is not None:
return self.manage_main(self, REQUEST, update_menu=0)
return id
#def addFunction(dispatcher, id, filename):
class VCUFileProduct(Implicit, Persistent, RoleManager, Item):
"""VCUFile product class, implements IVCUFile
Класс реализации продукта, самая сложная штука в проекте.
"""
# Реализуем интерфейс
implements(IVCUFile)
#Item requerements (класс Item содержит эти атрибуты)
meta_type = 'VCUFile'
id = ''
title = ''
# используется для декларации ограничений безопасности
security = ClassSecurityInfo()
def __init__(self, id, filename):
self.fid = ''
self.id = id
self.title = filename
security.declarePublic('getFID')
def getFID(self):
"""File ID
Реализуем метод интерфейса
"""
return self.fid
#class VCUFileProduct(Implicit, Persistent, RoleManager, Item)
InitializeClass(VCUFileProduct)
|
продукт и его фабрика.
Минималистичнее сделать трудно, наоборот,
сюда надо много добавить. К примеру, код
реализации вкладок для управлятора
ZMI; раскладку по привилегиям доступа.
vcufile\__init__.py
#!/usr/bin/env python
# -*- mode: python; coding: utf-8 -*-
# (c) Valik mailto:vasnake@gmail.com
__doc__ = """VCUFile initialization module. """
__version__ = '3.0.0.alpha'
# Самая простая часть (если не считать интерфейса), регистрация продукта
from vcufileproduct import VCUFileProduct, addForm, addFunction
def initialize(registrar):
'''Addon register method.
Call by Zope in startup time.
'''
registrar.registerClass(
VCUFileProduct,
constructors=(addForm, addFunction),
icon = 'www/vcufile16.png'
)
# help notes, by example from Products\ExternalMethod\
# чтобы это сработало, у меня сделан файл vcufile\help\VCUFile.stx
registrar.registerHelp()
registrar.registerHelpTitle('Zope Help')
|
регистрация продукта
в ZODB, при запуске Zope.
vcufile\help\VCUFile.stx
VCU File: File object for upload giant files with chunks, in resumable mode.
VCUFile is a regular file that can be upload to Zope server filesystem.
Upload process is resumable and can be completed in any time
from any computer.
|
минимальная справка
по продукту, просто текстовый файл
(первая строка добавлена только для
тут, в оригинальном файле ее нет).
Содержимое файлов *.TXT
я приводить не буду, оно достаточно
тривиальное.
Ну вот, заготовка есть.
Теперь то, что получилось можно добавить
в Zope. Для этого достаточно разместить
файлы в папке
c:\Zope\Instance\2.11.4\Products\VCUFile
и перезапустить Zope.
Если продукт зарегился
при запуске Zope, найти его можно тут
А раз есть продукт,
можно добавить объект в любую папку,
используя список
добавления, например.
На этом сегодня всё.
Позже я покажу как эту
заготовку превратить в нормальный,
полновесный, рабочий продукт. В частности,
надо сделать нормальную форму добавления;
нужна вкладка редактирования; с
безопасностью разобраться. И многое
другое.
Stay tuned.
kwords: web http chunked resumable upload, Zope, python, silverlight, javascript