aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/css/manage_problem.less13
-rw-r--r--src/css/style.less4
-rw-r--r--src/html/index.html2
-rw-r--r--src/html/manage_problem.html58
-rw-r--r--src/html/manage_square.html2
-rw-r--r--src/js/manage.js196
-rw-r--r--src/js/mod.js35
-rw-r--r--src/js/square.js8
-rwxr-xr-xsrc/py/backend_server.py7
-rwxr-xr-xsrc/py/imc/blobclient.py233
-rwxr-xr-xsrc/py/imc/blobhandle.py150
-rwxr-xr-xsrc/py/imc/blobserver.py263
-rw-r--r--src/py/square.py45
13 files changed, 953 insertions, 63 deletions
diff --git a/src/css/manage_problem.less b/src/css/manage_problem.less
new file mode 100644
index 0000000..ce7c5a4
--- /dev/null
+++ b/src/css/manage_problem.less
@@ -0,0 +1,13 @@
+@import 'color.less';
+@import 'mixin.less';
+
+#index_page{
+ div.oper{
+ text-align:center;
+ }
+ table.list{
+ tr.item{
+
+ }
+ }
+}
diff --git a/src/css/style.less b/src/css/style.less
index 7d6ef90..c03cec6 100644
--- a/src/css/style.less
+++ b/src/css/style.less
@@ -7,6 +7,10 @@
src:url('/DejaVuSansMono.woff');
}
+div.tiny_modal{
+ width:270px;
+ margin-left:-135px;
+}
div.small_modal{
width:570px;
margin-left:-285px;
diff --git a/src/html/index.html b/src/html/index.html
index 902411b..27efe74 100644
--- a/src/html/index.html
+++ b/src/html/index.html
@@ -26,6 +26,7 @@
<script src="/toj/js/index.js" type="text/javascript"></script>
<script src="/toj/js/user.js" type="text/javascript"></script>
<script src="/toj/js/notice.js" type="text/javascript"></script>
+<script src="/toj/js/mod.js" type="text/javascript"></script>
<script src="/toj/js/home.js" type="text/javascript"></script>
<script src="/toj/js/square.js" type="text/javascript"></script>
<script src="/toj/js/mail.js" type="text/javascript"></script>
@@ -42,6 +43,7 @@ $(document).ready(function(){
com.conn_callback.add(function(){
user.ready();
notice.ready();
+ mod.ready();
index.ready();
home.ready();
square.ready();
diff --git a/src/html/manage_problem.html b/src/html/manage_problem.html
new file mode 100644
index 0000000..abad7a3
--- /dev/null
+++ b/src/html/manage_problem.html
@@ -0,0 +1,58 @@
+<link href="/toj/css/manage_problem.css" rel="stylesheet">
+
+<div class="modal hide fade tiny_modal create">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+ <h3>建立題目</h3>
+ </div>
+ <div class="modal-body container-fluid">
+ <div class="row-fluid">
+ <div class="span13">
+ <label>題目名稱</label>
+ <input name="title" type="text">
+ <label>題目模組</label>
+ <select name="pmod"></select>
+ </div>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button class="btn btn-primary submit">確定</button>
+ <button class="btn cancel">取消</button>
+ </div>
+</div>
+<div class="modal hide fade tiny_modal set">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+ <h3>題目設定</h3>
+ </div>
+ <div class="modal-body container-fluid">
+ <div class="row-fluid">
+ <div class="span13">
+ <label>題目名稱</label>
+ <input name="title" type="text">
+ </div>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button class="btn btn-primary submit">確定</button>
+ <button class="btn cancel">取消</button>
+ </div>
+</div>
+
+<div class="row">
+ <div class="span2 offset1 oper">
+ <button class="btn create">建立題目</button>
+ </div>
+ <div class="span6">
+ <table class="table list">
+ <thead>
+ <tr>
+ <th class="span1">#</th>
+ <th class="span3">題目名稱</th>
+ <th class="span2"></th>
+ </tr>
+ </thead>
+ <tbody></tbody>
+ </table>
+ </div>
+</div>
diff --git a/src/html/manage_square.html b/src/html/manage_square.html
index 1f83dbc..900e280 100644
--- a/src/html/manage_square.html
+++ b/src/html/manage_square.html
@@ -17,6 +17,8 @@
<img class="img-polaroid hide logo"></img>
</div>
<div class="span7">
+ <label>方塊模組</label>
+ <select name="sqmod"></select>
<label>公開狀態</label>
<select name="hidden">
<option value=0>顯示</option>
diff --git a/src/js/manage.js b/src/js/manage.js
index cab6bcb..9767a38 100644
--- a/src/js/manage.js
+++ b/src/js/manage.js
@@ -5,10 +5,12 @@ var manage = new function(){
var j_index_page;
that.ready = function(){
- var j_tabnav_square;
-
var manage_node = new vus.node('manage');
var square_node = new vus.node('square');
+ var problem_node = new vus.node('problem');
+
+ var j_tabnav_square;
+ var j_tabnav_problem;
j_index_page = $('#index_page');
@@ -18,6 +20,7 @@ var manage = new function(){
index.clear_tabnav();
j_tabnav_square = index.add_tabnav('方塊','/toj/manage/square/');
+ j_tabnav_problem = index.add_tabnav('題目','/toj/manage/problem/');
com.call_backend('core/user/','list_auth',function(result){
console.log(result);
@@ -94,6 +97,9 @@ var manage = new function(){
return j_item;
}
function _update(){
+ var cate_defer = $.Deferred();
+ var sqmod_defer = $.Deferred();
+
com.call_backend('core/square/','list_category',function(result){
var i;
var data = result.data;
@@ -116,67 +122,95 @@ var manage = new function(){
create_tagbox_cate.set_words(catelist);
set_tagbox_cate.set_words(catelist);
- com.call_backend('core/square/','list_square',function(result){
- var i;
- var data = result.data;
- var items;
- var j_item;
- var sqo;
+ cate_defer.resolve();
+ }
+ });
+ com.call_backend('core/square/','list_sqmod',function(result){
+ var i;
+ var data = result.data;
+ var j_sqmod;
+ var j_option;
- if(com.is_callerr(result)){
- index.add_alert('','警告','管理發生錯誤');
- }else{
- items = j_list.find('tr.item');
-
- for(i = 0;i < Math.min(items.length,data.length);i++){
- sqo = data[i];
-
- if(sqo.start_time != null){
- sqo.start_time = new Date(sqo.start_time);
- }
- if(sqo.end_time != null){
- sqo.end_time = new Date(sqo.end_time);
- }
-
- _item_set($(items[i]),sqo.sqid,
- sqo.title,
- sqo.start_time,
- sqo.end_time,
- sqo.cateid,
- sqo.intro,
- sqo.logo,
- sqo.hidden);
- }
- for(;i < data.length;i++){
- sqo = data[i];
-
- j_item = _item_create(sqo.sqid,
- sqo.title,
- sqo.start_time,
- sqo.end_time,
- sqo.cateid,
- sqo.intro,
- sqo.logo,
- sqo.hidden);
- j_list.append(j_item);
+ if(com.is_callerr(result)){
+ index.add_alert('','警告','管理發生錯誤');
+ }else{
+ j_sqmod = j_create.find('[name="sqmod"]');
+ console.log(j_sqmod.length);
+ j_sqmod.empty();
+ for(i = 0;i < data.length;i++){
+ j_option = $('<option></option>');
+ j_option.attr('value',data[i].sqmodid);
+ j_option.text(data[i].sqmodname);
+
+ j_sqmod.append(j_option);
+ }
+
+ sqmod_defer.resolve();
+ }
+ });
+
+ $.when(cate_defer,sqmod_defer).done(function(cate){
+ com.call_backend('core/square/','list_square',function(result){
+ var i;
+ var data = result.data;
+ var items;
+ var j_item;
+ var sqo;
+
+ if(com.is_callerr(result)){
+ index.add_alert('','警告','管理發生錯誤');
+ }else{
+ items = j_list.find('tr.item');
+
+ for(i = 0;i < Math.min(items.length,data.length);i++){
+ sqo = data[i];
+
+ if(sqo.start_time != null){
+ sqo.start_time = new Date(sqo.start_time);
}
- for(;i < items.length;i++){
- $(items[i]).remove();
+ if(sqo.end_time != null){
+ sqo.end_time = new Date(sqo.end_time);
}
+
+ _item_set($(items[i]),sqo.sqid,
+ sqo.title,
+ sqo.start_time,
+ sqo.end_time,
+ sqo.cateid,
+ sqo.intro,
+ sqo.logo,
+ sqo.hidden);
}
- });
- }
- });
+ for(;i < data.length;i++){
+ sqo = data[i];
+
+ j_item = _item_create(sqo.sqid,
+ sqo.title,
+ sqo.start_time,
+ sqo.end_time,
+ sqo.cateid,
+ sqo.intro,
+ sqo.logo,
+ sqo.hidden);
+ j_list.append(j_item);
+ }
+ for(;i < items.length;i++){
+ $(items[i]).remove();
+ }
+ }
+ });
+ });
}
if(direct == 'in'){
com.loadpage('/toj/html/manage_square.html').done(function(){
var j_catebox;
- j_list = j_index_page.find('table.list');
+ j_tabnav_square.active();
+
j_create = j_index_page.find('div.create');
j_set = j_index_page.find('div.set');
- j_tabnav_square.active();
+ j_list = j_index_page.find('table.list > tbody');
j_catebox = j_create.find('div.catebox');
create_tagbox_cate = j_catebox.tagbox({'words':[],'restrict':true,'duplicate':false});
@@ -198,6 +232,7 @@ var manage = new function(){
var title = j_create.find('[name="title"]').val();
var intro = j_create.find('[name="intro"]').val();
var logo = j_create.find('[name="logo"]').val();
+ var sqmodid = parseInt(j_create.find('[name="sqmod"]').val());
var hidden = j_create.find('[name="hidden"]').val();
var tags = create_tagbox_cate.get_tag();
var cateid_list;
@@ -244,7 +279,7 @@ var manage = new function(){
j_create.modal('hide');
_update();
}
- },title,hidden,1,intro,logo,cateid_list);
+ },title,hidden,sqmodid,intro,logo,cateid_list);
});
j_create.find('button.cancel').on('click',function(e){
@@ -372,5 +407,62 @@ var manage = new function(){
return 'cont';
};
manage_node.child_set(square_node);
+
+ problem_node.url_chg = function(direct,url_upart,url_dpart,param){
+ var j_create;
+ var j_list;
+ var set_data;
+
+ function _item_set(j_item,proid,title,pmodid){
+ j_item.find('td.proid').text(proid);
+ j_item.find('td.title').text(title);
+
+ j_item.find('button.set').on('click',function(e){
+ set_data = {
+ 'proid':proid,
+ 'title':title,
+ 'pmodid':pmodid
+ };
+ });
+ j_item.find('button.del').on('click',function(e){
+
+ });
+ }
+ function _item_create(proid,title,pmodid){
+ var j_item = $('<tr><td class="proid"></td><td class="title"></td><td class="oper"><div class="btn-group"><button class="btn btn-small set"><i class="icon-cog"></i></button><button class="btn btn-small del"><i class="icon-trash"></i></button></div></td></tr>')
+
+ _item_set(j_item,proid,title,pmodid);
+
+ return j_item;
+ }
+ function _update(){
+
+ }
+
+ if(direct == 'in'){
+ j_tabnav_problem.active();
+
+ com.loadpage('/toj/html/manage_problem.html').done(function(){
+ j_create = j_index_page.find('div.create');
+ j_list = j_index_page.find('table.list > tbody');
+
+ j_index_page.find('button.create').on('click',function(e){
+ j_create.modal('show');
+ });
+
+ j_create.on('show',function(e){
+
+ });
+ j_create.on('hide',function(e){
+ j_create.find('input').val('');
+ });
+ });
+ }else{
+
+ }
+
+ return 'cont';
+ };
+ manage_node.child_set(problem_node);
};
};
diff --git a/src/js/mod.js b/src/js/mod.js
index b8cae5f..e626ff9 100644
--- a/src/js/mod.js
+++ b/src/js/mod.js
@@ -1,17 +1,48 @@
var mod = new function(){
var that = this;
+ that.curr_sqmod = null;
+
that.ready = function(){
var sq_node = new vus.node('sq');
sq_node.url_chg = function(direct,url_upart,url_dpart,param){
+ var sqid;
+
if(direct == 'in'){
+ index.set_menu('方塊');
+ index.clear_tabnav();
+
+ sqid = url_dpart[0];
+ sq_node.child_delayset(sqid);
+
+ com.call_backend('core/square/','get_square_info',function(result){
+ var data = result.data;
+ var sqmodname;
+
+ if(com.is_callerr(result)){
+ index.add_alert('','警告','開啓方塊發生錯誤');
+ }else{
+ index.set_title(data.title);
+
+ sqmodname = escape(data.sqmodname);
+ $.getScript('/toj/sqmod/' + sqmodname + '/js/' + sqmodname + '.js',function(script,status,xhr){
+ var sqid_node;
+
+ curr_sqmod = sqmodname;
+
+ sqid_node = new vus.node(sqid);
+ eval(sqmodname + '(sqid_node);');
+ sq_node.child_set(sqid_node);
+ });
+ }
+ },parseInt(sqid));
}else if(direct == 'out'){
-
+ eval(curr_sqmod + '.unload()');
}
- return 'stop';
+ return 'cont';
};
com.vus_root.child_set(sq_node);
};
diff --git a/src/js/square.js b/src/js/square.js
index b6ee4fa..9b5f684 100644
--- a/src/js/square.js
+++ b/src/js/square.js
@@ -30,7 +30,7 @@ var square = new function(){
j_oper = j_box.find('div.oper');
j_oper.empty();
if(active == null){
- j_oper.append('<button class="btn btn-primary join" data-loading-text="處理中">加入</button><button class="btn">開啓</button>');
+ j_oper.append('<button class="btn btn-primary join" data-loading-text="處理中">加入</button><a class="btn open">開啓</a>');
j_oper.find('button.join').on('click',function(e){
$(this).button('loading');
@@ -52,9 +52,9 @@ var square = new function(){
});
}else{
if(active== true){
- j_oper.append('<button class="btn btn-success quit" data-loading-text="處理中">退出</button><button class="btn">開啓</button>');
+ j_oper.append('<button class="btn btn-success quit" data-loading-text="處理中">退出</button><a class="btn open">開啓</a>');
}else{
- j_oper.append('<button class="btn btn-warning quit" data-loading-text="處理中">取消申請</button><button class="btn">開啓</button>');
+ j_oper.append('<button class="btn btn-warning quit" data-loading-text="處理中">取消申請</button><a class="btn open">開啓</a>');
}
j_oper.find('button.quit').on('click',function(e){
@@ -75,6 +75,8 @@ var square = new function(){
},id);
});
}
+
+ j_oper.find('a.open').attr('href','/toj/sq/' + id + '/');
}
function box_update(id,logo,title,start_time,end_time,intro,active){
var i;
diff --git a/src/py/backend_server.py b/src/py/backend_server.py
index e0faf38..5a58445 100755
--- a/src/py/backend_server.py
+++ b/src/py/backend_server.py
@@ -146,7 +146,7 @@ class BackendWorker(tornado.tcpserver.TCPServer):
@imc.async.caller
def _init_blobclient(self):
- '''blobclient = BlobClient(Proxy.instance,
+ blobclient = BlobClient(Proxy.instance,
TOJAuth.instance,
self._idendesc,
self._link,
@@ -160,8 +160,7 @@ class BackendWorker(tornado.tcpserver.TCPServer):
TOJBlobHandle.CREATE)
print(handle._fileno)
handle.write(bytes('Hello Data','utf-8'),0)
- handle.commit(False);'''
- pass
+ handle.commit(False);
def _conn_link(self,link):
def __handle_pend(conn):
@@ -381,7 +380,7 @@ if __name__ == '__main__':
worker_list = []
worker_list.append(Process(target = start_backend_worker,args = (81, )))
- worker_list.append(Process(target = start_backend_worker,args = (82, )))
+ #worker_list.append(Process(target = start_backend_worker,args = (82, )))
#worker_list.append(Process(target = start_backend_worker,args = (181, )))
#worker_list.append(Process(target = start_backend_worker,args = (182, )))
#worker_list.append(Process(target = start_backend_worker,args = (183, )))
diff --git a/src/py/imc/blobclient.py b/src/py/imc/blobclient.py
new file mode 100755
index 0000000..8d54ffe
--- /dev/null
+++ b/src/py/imc/blobclient.py
@@ -0,0 +1,233 @@
+#! /usr/bin/env python
+
+import os
+
+from imc.auth import Auth
+import imc.async
+from imc.proxy import Proxy
+
+from collections import Counter
+
+class BlobClient:
+ def __init__(self, proxy, auth, idendesc, link, serverlink,
+ location, cachetable, BlobHandle):
+ self._proxy = proxy
+ self._auth = auth
+ self._idendesc = idendesc
+ self._link = link
+ self._server = serverlink
+ self._is_connected = False
+ self._location = location
+ self._cachetable = cachetable
+ self.BlobHandle = BlobHandle
+ self._opencounts = Counter()
+ self._containers = dict()
+ self._deltags = set()
+ self.connect_server()
+ self._proxy.register_call('blobclient/', 'get_update',
+ self.get_update)
+
+ def __del__(self):
+ self._proxy.unregister_call('blobclient/', 'get_update')
+
+ def _server_call(self, func, *args):
+ server = self._server + 'blobserver/'
+ with Auth.change_current_iden(self._idendesc):
+ for i in range(5):
+ sta, ret = self._proxy.call(server, func, 10000,
+ self._link, *args)
+ if sta or (not sta and ret == 'Enoexist'):
+ break
+ return (sta, ret)
+
+ def _client_call(self, otherclient, func, *args):
+ otherclient += 'blobclient/'
+ with TOJAuth.change_current_iden(self._idendesc):
+ for i in range(5):
+ sta, ret = self._proxy.call(otherclient, func, 10000,
+ self._link, *args)
+ if sta or (not sta and ret == 'Enoexist'):
+ break
+ return (sta, ret)
+
+ def connect_server(self, serverlink=None):
+ if serverlink:
+ self._server = serverlink
+ sta, ret = self._server_call('connect_client',
+ self._cachetable.get_blob_list())
+ if sta:
+ if ret:
+ self._is_connected = True
+ else:
+ pass
+ else:
+ pass
+ if self._is_connected:
+ # TODO:
+ pass
+
+
+ def open_container(self, container, method):
+ sta, ret = self._server_call('open_container', container, method)
+ if not sta:
+ # TODO:
+ # pend operation when client can't imc call server
+ return None
+ if ret:
+ self._containers[container] = method
+ return True
+ else:
+ return False
+
+ def close_container(self, container):
+ sta, ret = self._server_call('close_container', container)
+ if not sta:
+ # TODO:
+ # pend operation when client can't imc call server
+ return None
+ if ret:
+ del self._containers[container]
+ return True
+ else:
+ return False
+
+ # TODO:
+ # periodically call this function to clean old data and do something else
+ # ex: send pending operation
+ def sync(self):
+ for blobname_rev in self._deltags:
+ self.del_real_blob(blobname_rev)
+ # for container in self._containers:
+ # if self._containers[container] == 'ALWAYS':
+ # for blob in self._cachetable.get_blob_list(container):
+ # self.update(blob)
+
+ @imc.async.caller
+ def get_update(self, blobname, info, filekey=None):
+ if info is None:
+ self.del_blob(blobname)
+ elif filekey is not None:
+ rev = info['rev']
+ if self.recv_blob(filekey, blobname, rev).wait() == 'Success':
+ self.update_blob(blobname, info)
+ sta, ret = self._server_call('recv_update_result',
+ blobname, "Success", rev)
+ if not sta:
+ # TODO:
+ pass
+ else:
+ self.update_blob(blobname, info)
+ return self._link
+
+ def update(self, blobname):
+ cacherev = self._cachetable.get_blob_info(blobname, 'rev')
+ if cacherev == None:
+ cacherev = 0
+
+ sta, ret = self._server_call('check_blob', blobname, cacherev)
+
+ if not sta:
+ # TODO:
+ # pend operation when client can't imc call server
+ return None
+ if ret is None:
+ return True
+ elif not ret:
+ self._cachetable.del_blob(blobname)
+ if cacherev:
+ self.del_real_blob(''.join([blobname, '_', str(cacherev)]))
+ return None
+ else:
+ info = ret['info']
+ rev = info['rev']
+ for i in range(4):
+ rst = self.recv_blob(ret['filekey'], blobname, rev).wait()
+ sta, ret = self._server_call('recv_update_result', blobname,
+ rst, rev, True)
+
+ if not sta:
+ pass
+ # TODO:
+ if 'Success' == ret:
+ self.update_blob(blobname, info)
+ return True
+
+ return False
+
+ def commit(self, commit_info, force_flag, blobhandle):
+ filekey = None
+ if not commit_info['deltag'] and commit_info['written']:
+ result = self.send_blob(blobhandle._tmpfile)
+ filekey = result.filekey
+ sta, ret = self._server_call('recv_commit', commit_info,
+ force_flag, filekey)
+ if not sta:
+ # TODO:
+ # pend operation when client can't imc call server
+ return False
+ # TODO:
+ # if commit success , copy tmpfile to location
+
+ # TODO:
+ # opencounts ?
+ def send_blob(self, blobpath, otherclient=None):
+ if otherclient is None:
+ return self._proxy.sendfile(self._server, blobpath)
+ else:
+ return self._proxy.sendfile(otherclient, blobpath)
+
+ def recv_blob(self, filekey, blobname, rev):
+ blobpath = os.path.join(self._location, blobname + '_' + str(rev))
+ return self._proxy.recvfile(filekey, blobpath)
+
+ def update_blob(self, blobname, info):
+ rev = self._cachetable.get_blob_info(blobname, 'rev')
+ blobname_rev = ''.join([blobname, '_', str(rev)])
+ self.del_real_blob(blobname_rev)
+ self._cachetable.update_blob(blobname, info)
+
+ def del_blob(self, blobname):
+ rev = self._cachetable.get_blob_info(blobname, 'rev')
+ blobname_rev = ''.join([blobname, '_', str(rev)])
+ self._cachetable.del_blob(blobname)
+ self.del_real_blob(blobname_rev)
+
+ def del_real_blob(self, blobname_rev):
+ if self._opencounts[blobname_rev] == 0:
+ path = os.path.join(self._location, blobname_rev)
+ self.BlobHandle.del_blob(path)
+ else:
+ self._deltags.add(blobname_rev)
+
+ def open(self, container, blobname, flag):
+ if container not in self._containers:
+ raise Exception("this container isn't open")
+ blob = container + '_' + blobname
+ is_existent = self.update(blob)
+ if is_existent is None:
+ if (not flag & self.BlobHandle.WRITE or
+ not flag & self.BlobHandle.CREATE):
+ raise Exception("the blob doesn't exist, so you must "
+ "add a create flag")
+ elif not is_existent:
+ pass
+ try:
+ info = self._cachetable.get_blob_info(blob)
+ if info is None:
+ info = {'container': container,
+ 'rev': 0,
+ 'metadata': '',
+ 'size': None,
+ 'commit_time': None}
+ handle = self.BlobHandle(blob, info, flag, self)
+ except:
+ raise
+ else:
+ blob += '_' + str(handle.get_rev())
+ self._opencounts[blob] += 1
+ return handle
+
+ def close(self, blobhandle):
+ blob = ''.join([blobhandle._name, '_',
+ str(blobhandle.get_rev())])
+ self._opencounts[blob] -= 1
diff --git a/src/py/imc/blobhandle.py b/src/py/imc/blobhandle.py
new file mode 100755
index 0000000..b957162
--- /dev/null
+++ b/src/py/imc/blobhandle.py
@@ -0,0 +1,150 @@
+#! /usr/bin/env python
+
+from abc import abstractmethod
+
+class BlobHandle:
+ READ = 0x1
+ WRITE = 0x2
+ CREATE = 0x4
+ DELETE = 0x8
+ WRITEMETA = 0x10
+ def __init__(self, name, info, flag, blobclient):
+ self._name = name
+ self._info = info
+ self._flag = flag
+ self._blobclient = blobclient
+ self._location = self._blobclient._location
+ self._is_closed = False
+ self._deltag = False
+ self._written = False
+ self._createtag = False
+ self._need_commit = False
+ self._tmpfile = None
+ self._blobpath = ''.join([self._location, self._name,
+ '_', str(self.get_rev())])
+ if flag & BlobHandle.CREATE:
+ if not flag & BlobHandle.WRITE:
+ raise Exception("invalid flag")
+ else:
+ self._need_commit = True
+ self._createtag = True
+ self._written = True
+ if flag & BlobHandle.WRITE:
+ self._tmpfile = self.gen_tmp()
+
+ def __del__(self):
+ self._del_tmp()
+ self._blobclient.close(self)
+
+ def create(self):
+ self._create(self.location + self._name)
+
+ def read(self, length, offset):
+ if self._is_closed:
+ raise Exception("This Blob is closed")
+ if not self._flag & BlobHandle.READ:
+ raise Exception("Permission Denied")
+ return self._read(length, offset)
+
+ def write(self, data, offset):
+ if self._is_closed:
+ raise Exception("This Blob is closed")
+ if not self._flag & BlobHandle.WRITE:
+ raise Exception("Permission Denied")
+ self._need_commit = True
+ written_bytes = self._write(data, offset)
+ self._written = bool(written_bytes)
+ self._info['size'] = self._get_size()
+ return written_bytes
+
+ def rename(self, newname):
+ if self._is_closed:
+ raise Exception("This Blob is closed")
+ if not self._flag & BlobHandle.DELETE:
+ raise Exception("Permission Denied")
+ self._need_commit = True
+
+ def delete(self, deltag=True):
+ if self._is_closed:
+ raise Exception("This Blob is closed")
+ if not self._flag & BlobHandle.DELETE:
+ raise Exception("Permission Denied")
+ self._need_commit = True
+ self._deltag = deltag
+
+ def close(self):
+ self._is_closed = True
+ if self._flag != BlobHandle.READ:
+ self._blobclient.close(self)
+
+ def get_metadata(self):
+ if self._is_closed:
+ raise Exception("This Blob is closed")
+ return self._info['metadata']
+
+ def set_metadata(self, metadata):
+ if self._is_closed:
+ raise Exception("This Blob is closed")
+ if not self._flag & BlobHandle.WRITEMETA:
+ raise Exception("Permission Deniedd")
+ self._info['metadata'] = metadata
+ self._need_commit = True
+
+ def get_rev(self):
+ if self._is_closed:
+ raise Exception("This Blob is closed")
+ return self._info['rev']
+
+ def get_container(self):
+ if self._is_closed:
+ raise Exception("This Blob is closed")
+ return self._info['container']
+
+ def get_size(self):
+ if self._is_closed:
+ raise Exception("This Blob is closed")
+ return self._info['size']
+
+ def commit(self, flag):
+ if self._is_closed:
+ raise Exception("This Blob is closed")
+ if not self._need_commit:
+ return False
+ commit_info = dict()
+ commit_info['blobname'] = self._name
+ if self._deltag:
+ commit_info['deltag'] = True
+ else:
+ commit_info['deltag'] = False
+ commit_info['createtag'] = self._createtag
+ commit_info['info'] = self._info
+ commit_info['written'] = self._written
+ return self._blobclient.commit(commit_info, flag, self)
+
+ @abstractmethod
+ def gen_tmp(self):
+ # return tmp file path
+ pass
+
+ @abstractmethod
+ def del_tmp(self):
+ pass
+
+ @abstractmethod
+ def _read(self, length, offset):
+ pass
+
+ @abstractmethod
+ def _write(self, data, offset):
+ pass
+
+ @abstractmethod
+ def _get_size(self):
+ pass
+
+ @staticmethod
+ @abstractmethod
+ def del_blob(blobpath):
+ pass
+
+
diff --git a/src/py/imc/blobserver.py b/src/py/imc/blobserver.py
new file mode 100755
index 0000000..73bc143
--- /dev/null
+++ b/src/py/imc/blobserver.py
@@ -0,0 +1,263 @@
+#! /usr/bin/env python
+
+import os
+
+from imc.auth import Auth
+import imc.async
+from imc.proxy import Proxy
+
+from collections import Counter
+
+class BlobServer:
+ def __init__(self, proxy, auth, idendesc, link,
+ location, blobtable, BlobHandle):
+
+ self._proxy = proxy
+ self._auth = auth
+ self._idendesc = idendesc
+ self._link = link
+ self._location = location
+ self._blobtable = blobtable
+ self.BlobHandle = BlobHandle
+ self._clients = {}
+ self._containers = dict.fromkeys(self._blobtable.get_container_list(),
+ dict())
+ self._proxy.register_call('blobserver/', 'connect_client',
+ self.connect_client)
+ self._proxy.register_call('blobserver/', 'open_container',
+ self.open_container)
+ self._proxy.register_call('blobserver/', 'close_container',
+ self.close_container)
+ self._proxy.register_call('blobserver/', 'check_blob',
+ self.check_blob)
+ self._proxy.register_call('blobserver/', 'recv_update_result',
+ self.recv_update_result)
+ self._proxy.register_call('blobserver/', 'recv_commit',
+ self.recv_commit)
+
+ def __del__(self):
+ self._proxy.unregister_call('blobserver/', 'connect_client')
+ self._proxy.unregister_call('blobserver/', 'open_container')
+ self._proxy.unregister_call('blobserver/', 'close_container')
+ self._proxy.unregister_call('blobserver/', 'check_blob')
+ self._proxy.unregister_call('blobserver/', 'recv_update_result')
+ self._proxy.unregister_call('blobserver/', 'recv_commit')
+
+ def _client_call(self, client, func, timeout=10000, *args):
+ client += 'blobclient/'
+ with Auth.change_current_iden(self._idendesc):
+ for i in range(5):
+ sta, ret = self._proxy.call(client, func, timeout, *args)
+ if sta or (not sta and ret == 'Enoexist'):
+ break
+ return (sta, ret)
+
+ def _client_call_async(self, client, func, callback,
+ timeout=10000, *args, **kwargs):
+ client += 'blobclient/'
+ with Auth.change_current_iden(self._idendesc):
+ for i in range(5):
+ sta, ret = self._proxy.call_async(client, func, timeout,
+ callback, *args)
+ if sta or (not sta and ret == 'Enoexist'):
+ break
+ return (sta, ret)
+
+ @imc.async.caller
+ def connect_client(self, client, cache_list):
+ if client not in self._clients:
+ self._clients.update({client: cache_list})
+ else:
+ self._clients[client] = cache_list
+
+ def disconnect_client(self, client):
+ try:
+ self._clients.pop[client]
+ except ValueError:
+ raise Exception("this client doesn't exist")
+
+ def create_container(self, container):
+ self._blobtable.create_container(container)
+ self._containers[container] = dict()
+
+ def del_container(self, container):
+ try:
+ self._blobtable.del_container(container)
+ del self._containers[container]
+ except:
+ raise
+
+ @imc.async.caller
+ def open_container(self, client, container, method):
+ try:
+ self._containers[container][client] = method
+ except KeyError:
+ return False
+ else:
+ return True
+
+ @imc.async.caller
+ def close_container(self, client, container):
+ try:
+ self._containers[container].pop(client)
+ except KeyError:
+ raise
+
+ def update_blob(self, blobname, info):
+ self._blobtable.update_blob(blobname, info)
+
+ def del_blob(self, blobname):
+ rev = self._blobtable.get_blob_info(blobname, 'rev')
+ blobname_rev = ''.join([blobname, '_', str(rev)])
+ self._blobtable.del_blob(blobname)
+ self.del_real_blob(blobname_rev)
+
+ def del_real_blob(self, blobname_rev):
+ blobpath = self._location + blobname_rev
+ self.BlobHandle.del_blob(blobpath)
+
+ def send_blob(self, client, blobname):
+ rev = str(self._blobtable.get_blob_info(blobname, 'rev'))
+ blobpath = os.path.join(self._location, blobname + '_' + rev)
+ return self._proxy.sendfile(client, blobpath)
+
+ def recv_blob(self, filekey, blobname, rev):
+ blobpath = os.path.join(self._location, blobname + '_' + str(rev))
+ ret = self._proxy.recvfile(filekey, blobpath)
+
+ return ret
+
+ @imc.async.caller
+ def check_blob(self, client, blobname, cacherev):
+ rev = self._blobtable.get_blob_info(blobname, 'rev')
+ if rev is None:
+ return False
+ elif cacherev < rev:
+ result = self.send_blob(client, blobname)
+ response = {'filekey': result.filekey,
+ 'info': self._blobtable.get_blob_info(blobname)}
+ return response
+ else:
+ return None
+
+ @imc.async.caller
+ def recv_update_result(self, client, blobname, result,
+ cacherev, retry=False):
+ if client not in self._clients:
+ return None
+ else:
+ if result == 'Success':
+ self._clients[client].append({blobname: cacherev})
+ return 'Success'
+ elif retry:
+ result = self.send_blob(client, blobname)
+ response = {'filekey': result.filekey,
+ 'info': self._blobtable.get_blob_info(blobname)}
+ return response
+ else:
+ return 'Finish'
+
+ def send_update(self, clients, blobname, info, written):
+ result_table = dict.fromkeys(clients)
+ def recv_result(result):
+ nonlocal result_table
+ nonlocal blobname
+ nonlocal info
+ sta, client = result
+ # TODO:
+ # limit retry
+ if not sta:
+ self._client_call_async(client, 'get_update',
+ recv_result,
+ blobname, info,
+ result_table[client].filekey)
+ else:
+ if result_table[client] is None:
+ result_table.pop(client)
+ elif result_table[client].wait() != 'Success':
+ result_table[client] = self.send_blob(client, blobname)
+ self._client_call_async(client, 'get_update',
+ recv_result,
+ blobname, info,
+ result_table[client].filekey)
+ else:
+ result_table.pop(client)
+
+ for client in clients:
+ if written:
+ result_table[client] = self.send_blob(client, blobname)
+ else:
+ result_table[client] = None
+ sta, ret = self._client_call(client, 'get_update',
+ recv_result,
+ blobname, info,
+ result_table[client].filekey)
+ if not sta:
+ # TODO:
+ pass
+
+ @imc.async.caller
+ def recv_commit(self, client, commit_info, force_flag, filekey=None):
+ blobname = commit_info['blobname']
+ info = commit_info['info']
+ rev = self._blobtable.get_blob_info(blobname, 'rev')
+ if rev is None:
+ if commit_info['createtag']:
+ rev = 0
+ else:
+ return False
+ elif info['rev'] < rev and not force_flag:
+ return False
+
+ if commit_info['deltag']:
+ self.del_blob(blobname)
+ clients = set()
+ for needed_client, method in (
+ self._containers[info['container']].items()
+ ):
+ if method == "ACTIVE":
+ clients.add(needed_client)
+ clients.discard(client)
+ self.send_update(clients, blobname, None, False)
+ result = True
+ else:
+ info['rev'] = rev + 1
+ if commit_info['written']:
+ status = self.recv_blob(filekey, blobname, rev + 1)
+ result = status.wait()
+ if rev:
+ self.del_real_blob(''.join([blobname, '_', str(rev)]))
+ else:
+ result = True
+ if result:
+ self.update_blob(blobname, info)
+ clients = set()
+ for needed_client, method in (
+ self._containers[info['container']].items()):
+ if method == "ACTIVE":
+ clients.add(needed_client)
+ clients.discard(client)
+ self.send_update(clients, blobname,
+ info, commit_info['written'])
+
+ return True
+ else:
+ return False
+
+
+
+################### Testing Code #######################
+'''
+if __name__ == '__main__':
+ global blob_serv
+
+ blob_serv = BlobServer()
+ blob_serv.listen(5730)
+
+ #http_serv = tornado.httpserver.HTTPServer(tornado.web.Application([
+ # ('/conn',WebConnHandler),
+ #]))
+ #http_serv.listen(83)
+
+ tornado.ioloop.IOLoop.instance().start()
+'''
diff --git a/src/py/square.py b/src/py/square.py
index e00c12b..bf16621 100644
--- a/src/py/square.py
+++ b/src/py/square.py
@@ -49,6 +49,10 @@ class SquareMg:
'core/square/', 'delete_square', self.delete_square)
Proxy.instance.register_call(
'core/square/', 'set_square', self.imc_set_square)
+ Proxy.instance.register_call(
+ 'core/square/', 'get_square_info', self.get_square_info)
+ Proxy.instance.register_call(
+ 'core/square/', 'list_sqmod', self.list_sqmod)
def unload(self):
Proxy.instance.unregister_call(
@@ -65,6 +69,10 @@ class SquareMg:
'core/square/', 'delete_square')
Proxy.instance.unregister_call(
'core/square/', 'set_square')
+ Proxy.instance.unregister_call(
+ 'core/square/', 'get_square_info')
+ Proxy.instance.unregister_call(
+ 'core/square/', 'list_sqmod')
@TOJAuth.check_access(_accessid, TOJAuth.ACCESS_EXECUTE)
def load_square(self, sqid):
@@ -292,11 +300,11 @@ class SquareMg:
uid = mod.UserMg.get_current_uid()
- ret = self._list_square_category(cateid, uid)
+ ret = self._list_square(cateid, uid)
return ret
- def _list_square_category(self, cateid, uid):
+ def _list_square(self, cateid, uid):
cur = self.db.cursor()
sqlsel = ('SELECT "SQUARE"."sqid", "title", "start_time", "end_time", '
'"hidden", "sqmodid", "intro", "logo", "cateid"')
@@ -356,6 +364,20 @@ class SquareMg:
return ret
@imc.async.caller
+ def get_square_info(self, sqid):
+ if(
+ type(sqid) != int
+ ):
+ return 'Eparameter'
+
+ ret = self.get_square_info_by_sqid(sqid)
+
+ if ret == None:
+ return 'Esqid'
+
+ return ret
+
+ @imc.async.caller
def create_group():
pass
@@ -438,6 +460,23 @@ class SquareMg:
return cate_list
@imc.async.caller
+ def list_sqmod(self):
+ cur = self.db.cursor()
+ sqlstr = ('SELECT "sqmodid", "sqmodname", "info" FROM "SQMOD" '
+ 'ORDER BY "sqmodid" ASC;')
+ cur.execute(sqlstr)
+
+ sqmod_list = []
+ for data in cur:
+ obj = {}
+ obj['sqmodid'] = data[0]
+ obj['sqmodname'] = data[1]
+ obj['info'] = data[2]
+ sqmod_list.append(obj)
+
+ return sqmod_list
+
+ @imc.async.caller
def join_square(self, sqid):
if(
type(sqid) != int
@@ -540,6 +579,8 @@ class SquareMg:
if 0 in ret['cateid']:
ret['cateid'] = []
+ ret['sqmodname'] = self.get_sqmodname_by_sqmodid(ret['sqmodid'])
+
return ret
def does_sqid_exist(self, sqid):