Commits

codernity committed 8a37cc6

Some changes:
- IndexCreator in interface / app
- HTTP server updated a bit

Comments (0)

Files changed (9)

CodernityDBHTTP/app.py

 else:
     has_json = True
 
-from misc import with_basic_auth, default_method, static_file, auth_static_file, tuple_funct, fixed_user_pass, make_one_item_iter, values_to_base, handle_exception
+from misc import with_basic_auth, default_method, static_file, auth_static_file, tuple_funct, fixed_user_pass, make_one_item_iter, values_to_base, handle_exception, open_with_autosave
 from all_exceptions import *
 from CodernityDB.database import header_for_indexes
 from CodernityDB import __version__ as __db__version__
     from __init__ import __version__ as __srv__version__
 
 
+MAX_POST_SIZE = 1024 * 1024
+
+
 content_types = {
     'application/json': (json.loads, make_one_item_iter(json.dumps)),
 }
                 except ValueError:
                     return handle_exception(start_response, output_f, inc_type, 400, 'You have to specify body')
                 else:
+                    if l > self.MAX_POST_SIZE:
+                        return handle_exception(start_response, output_f, inc_type, 400, 'Too big body max allowed %d bytes' % self.MAX_POST_SIZE)
                     if l != 0:
                         inp = env.get('wsgi.input')
                         try:
                 return handle_exception(start_response, output_f, inc_type)
 
 
-def get_app(db_class, db_path, cfg):
+def get_app(db_class, db_path, cfg, cfg_path):
 
     def auth_function(target, realm="Admin"):
         return with_basic_auth(target, realm, fixed_user_pass('admin', cfg.get('admin_pass')))
         'compact_index': auth_function(db.compact_index),
         'reindex': auth_function(db.reindex),
         'reindex_index': auth_function(db.reindex_index),
-        'open': auth_function(db.open),
+        'open': auth_function(open_with_autosave(db, cfg_path, cfg)),
         'opened': auth_function(lambda: db.opened),
         'destroy': auth_function(db.destroy),
         'exists': auth_function(db.exists),
         '_ui': auth_static_file(os.path.abspath(_ui_path), static_file)
     }
 
-    return CodernityDBApp(routes, static_routes).codernitydb_app
+    app = CodernityDBApp(routes, static_routes)
+    app.MAX_POST_SIZE = cfg.get('max_post_size', MAX_POST_SIZE)
+    return app.codernitydb_app

CodernityDBHTTP/config.json

 {
-    "server": "auto",
-    "port": 9876,
-    "bind": "0.0.0.0",
-    "db_path": null,
-    "admin_pass": "password",
-    "backlog": 50
+    "admin_pass": "password", 
+    "auto_save": 0, 
+    "backlog": 50, 
+    "bind": "0.0.0.0", 
+    "db_path": null, 
+    "port": 9876, 
+    "server": "auto"
 }

CodernityDBHTTP/interface/index.html

             <div data-bind="if: dbInit">
                 <h2>Create or open database</h2>
                 <div class="alert alert-info">
-                    <strong>Note:</strong> If database from provided path is exist, system will try to open it instead create.
+                    <strong>Note:</strong> If there will be database in location that you enter, it will be opened instead of created.
                 </div>
                 <form class="form-horizontal" method="post" data-bind="submit: db_init">
                     <div class="control-group">
                 </div>
             </div>
             <!-- modal -->
-            <div class="modal hide" id="destroy_db_modal">
+            <div class="modal hide" tabindex="-1" id="destroy_db_modal">
                 <div class="modal-header">
                     <a class="close" data-dismiss="modal">x</a>
                     <h3>Are you sure to destroy?</h3>
             <!-- newIndex -->
             <div data-bind="with: newIndex">
                 <!-- modal -->
-                <div class="modal hide fade" id="save_plain_modal">
+                <div class="modal hide fade" tabindex="-1" id="save_plain_modal">
                     <div class="modal-header">
                         <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                         <h3>Save index</h3>
                     <fieldset>
                         <div class="control-group">
                             <div class="controls">
-                                <textarea style="width: 100%; height: 200px;" data-bind="codeMirror: index_code, codeMirrorOptions: {mode: {name: 'python'}, lineNumbers: true }" type="text" class="input-xlarge" id="index_code"></textarea>
+                            <textarea style="width: 100%; height: 200px;" data-bind="codeMirror: index_code, codeMirrorOptions: {mode: {name: 'python'}, lineNumbers: true }" type="text" class="input-xlarge" id="index_code"></textarea>
                             </div>
                         </div>
                     </fieldset>
                 </form>
                 <div class="form-actions">
                     <button data-bind='click: open_save_modal, enable: index_code().length' class="btn btn-primary"><i class="icon-ok icon-white"></i> Save</button>
-                    <button class="btn" data-bind="click: insert_plain"><i class="icon-plus"></i> Insert plain</button>
+                    <button class="btn" data-bind="click: insert_plain, visible: is_normal_code"><i class="icon-plus"></i> Insert plain</button>
+                    
+                    <!-- ko ifnot: is_normal_code() -->
+                    <button class="btn" id="btn_switch_new_code" data-bind="click: switch_new_code"><i class="icon-share-alt"></i> Python code</button>
+                    <a class="btn" href="http://labs.codernity.com/codernitydb/database_indexes.html#easier-way-of-creating-indexes" target="_blank"><i class="icon-question-sign"></i> Syntax Help</a>
+                    <!-- /ko -->
+                    <!-- ko if: is_normal_code() -->
+                    <button class="btn" id="btn_switch_new_code" data-bind="click: switch_new_code"><i class="icon-share-alt"></i> Simplified code</button>
+                    <!-- /ko -->
                 </div>
             </div>
             <!-- newIndex -->
             <!-- singleIndexDetails -->
             <div data-bind="with: singleIndexDetails">
                 <!-- modal -->
-                <div class="modal hide fade" id="save_edit_plain_modal">
+                <div class="modal hide fade" tabindex="-1" id="save_edit_plain_modal">
                     <div class="modal-header">
                         <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                         <h3>Save index</h3>
                     <div class="btn-group left">
                         <button class="btn" data-bind="click: view"><i class="icon-zoom-in"></i> View</button>
                         <button class="btn" data-bind="click: toggle_code_details"><i class="icon-eye-open"></i> <span data-bind="text: code_details_text()"></span></button>
+                        <!-- ko ifnot: show_code() -->
                         <button class="btn" data-bind="click: compact"><i class="icon-repeat"></i> Compact</button>
                         <button class="btn" data-bind="click: count_all"><i class="icon-info-sign"></i> Count</button>
+                        <!-- /ko -->
+                        <!-- ko if: show_code() -->
+                            <!-- ko ifnot: is_normal_code() -->
+                                <button class="btn" id="btn_switch_code" data-bind="click: switch_code"><i class="icon-share-alt"></i> Python code</button>
+                                <a class="btn" href="http://labs.codernity.com/codernitydb/database_indexes.html#easier-way-of-creating-indexes" target="_blank"><i class="icon-question-sign"></i> Syntax Help</a>
+                            <!-- /ko -->
+                            <!-- ko if: is_normal_code() -->
+                                <button class="btn" id="btn_switch_code" data-bind="click: switch_code"><i class="icon-share-alt"></i> Simplified code</button>
+                            <!-- /ko -->
+                        <!-- /ko -->
                     </div>
                     <div class="btn-group right" data-bind="if: name != 'id'">
                         <!-- ko if: show_code() -->
                     <li class="active" data-bind="text: _id"></li>
                 </ul>
                 <!-- /ko -->
-                <div class="modal hide" id="delete_doc_modal">
+                <div class="modal hide" tabindex="-1" id="delete_doc_modal">
                     <div class="modal-header">
                         <a class="close" data-dismiss="modal">x</a>
                         <h3>Are you sure to delete?</h3>
                     <fieldset>
                         <div class="control-group">
                             <div class="controls">
-                                <textarea style="width: 100%; height: 200px;" data-bind="codeMirror: document_data, codeMirrorOptions: {mode: {name: 'javascript', json: true}, lineNumbers: true }" type="text" class="input-xlarge" id="document_content"></textarea>
+                            <textarea style="width: 100%; height: 200px;" data-bind="codeMirror: document_data, codeMirrorOptions: {mode: {name: 'javascript', json: true}, lineNumbers: true }" type="text" class="input-xlarge" id="document_content"></textarea>
                             </div>
                         </div>
                     </fieldset>
             </footer>
         </div>
 
+        <div id="notifier" tabindex="-1" class="modal hide fade">
+            <div class="modal-header">
+                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+                <h3></h3>
+            </div>
+            <div class="modal-body">
+                <pre></pre>
+            </div>
+            <div class="modal-footer">
+                <a class="btn" data-dismiss="modal">Cancel</a>
+            </div>
+        </div>
+
         <script src="/_ui/scripts/lib/jquery-1.7.2.min.js" type="text/javascript"></script>
         <script src="/_ui/bootstrap/js/bootstrap-dropdown.js"></script>
         <script src="/_ui/bootstrap/js/bootstrap-modal.js"></script>

CodernityDBHTTP/interface/scripts/app.js

 
 (function() {
 
+    var my_cms = {};
+    var error_marker = null;
     $.ajaxSetup({
         "contentType": "application/json",
     })
         console.log(event)
         console.log('ajaxSettings:')
         console.log(ajaxSettings)
+        
+        if(jqXHR.status == 400 && (ajaxSettings['url'] == '/add_index' || ajaxSettings['url'] == '/edit_index')) {
+            var ls = $.parseJSON(jqXHR.responseText)['reason']
+            ls = RegExp('\\(in line: ([0-9]+)\\)').exec(ls)
+            if (error_marker) {
+                error_marker.clean()
+            }
+            if (ls){
+                error_marker = my_cms['index_code'].markText({line : ls[1]-1,ch : 0},{line : ls[1]-1,ch : 99999},"cm-error")
+            }
+        }
     })
 
     $('#indexDetailsNavigation').live('click', function(){
     });
 
     ko.bindingHandlers.codeMirror = function() {
-        var my_cm = null;
         return {
             init: function(element, valueAccessor, allBindingsAccessor, context) {
-                var options = allBindingsAccessor().codeMirrorOptions || {}
-                var modelValue = valueAccessor()
-                var value = ko.utils.unwrapObservable(valueAccessor())
-                var el = $(element)
+              var options = allBindingsAccessor().codeMirrorOptions || {}
+              var modelValue = valueAccessor()
+              var value = ko.utils.unwrapObservable(valueAccessor())
+              var el = $(element)
 
-                setTimeout(function() {
-                    options.onChange = function(from, to, text, next) {
-                        if (ko.isWriteableObservable(modelValue)) {
-                            modelValue(my_cm.getValue())
-                        }
-                    }
-                    my_cm = CodeMirror.fromTextArea(element, options)
-                    if(value) {
-                        my_cm.setValue(value)
-                    }
-                }, 0)
+              setTimeout(function() {
+                      options.onChange = function(from, to, text, next) {
+                      if (ko.isWriteableObservable(modelValue)) {
+                      modelValue(my_cms[el.attr('id')].getValue())
+                      }
+                      }
+                      my_cms[el.attr('id')] = CodeMirror.fromTextArea(element, options)
 
-                ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
-                    setTimeout(function(){
-                        my_cm.toTextArea()
-                    }, 0)
-                });
+                      if(value) {
+                      my_cms[el.attr('id')].setValue(value)
+                      }
+                      }, 0)
 
-            }
-            , update: function(element, valueAccessor) {
-                var el = $(element)
-                var value = ko.utils.unwrapObservable(valueAccessor())
-                var id = el.attr('id')
-                var update = function(val) {
-                    var update_tries = 0
-                    function later() {
-                        setTimeout(function() {
-                            updater()
-                        }, 5)
-                    }
-                    function updater() {
-                        if(!my_cm) {
-                            update_tries++
-                            if (update_tries < 5) {
-                                later()
-                            } else {
-                                console.log("Failed to activate codemirror")
-                            }
-                        } else {
-                            if (val) {
-                                if(val != my_cm.getValue()) {
-                                    my_cm.setValue(val)
-                                }
-                            }
-                        }
-                    }
-                    return updater
-                }
-                if (id !== undefined && id !== '') {
-                    var upd = update(value)
-                    upd()
-                }
-            }
+          ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
+                  setTimeout(function(){
+                      my_cms[el.attr('id')].toTextArea()
+                      }, 0)
+                  });
+
+      }
+      , update: function(element, valueAccessor) {
+          var el = $(element)
+              var value = ko.utils.unwrapObservable(valueAccessor())
+              var id = el.attr('id')
+              var update = function(val) {
+                  var update_tries = 0
+                      function later() {
+                          setTimeout(function() {
+                                  updater()
+                                  }, 5)
+                      }
+                  function updater() {
+                      if(!my_cms[el.attr('id')]) {
+                          update_tries++
+                              if (update_tries < 5) {
+                                  later()
+                              } else {
+                                  console.log("Failed to activate codemirror")
+                              }
+                      } else {
+                          if (val != null) {
+                              if(val != my_cms[el.attr('id')].getValue()) {
+                                  my_cms[el.attr('id')].setValue(val)
+                              }
+                          }
+                          if (error_marker) {
+                              error_marker.clear()
+                              error_marker = null
+                          }
+                      }
+                  }
+                  return updater
+              }
+          if (id !== undefined && id !== '') {
+              var upd = update(value)
+                  upd()
+          }
+      }
         }
     }()
 
         self.show_code = ko.observable(null)
         self.class_names = ko.observableArray([])
         self.class_name = ko.observable('')
+        self.is_normal_code = ko.observable(true)
+         
+        if (name == null) {
+            self.simplified_code = ""
+            self.python_code = ""
+        }
 
         self.validation = new kk.Validation( self, {
             form_name : [   new kk.validators.Required("Enter name"),
 
         self.open_save_modal = function() {
             // look for classes in index code
-            var classes = self.index_code().match(/^class\s+[a-zA-Z_]\w*[\(|:]/gm)
+            if (self.is_normal_code()) {
+                var classes = self.index_code().match(/^class\s+[a-zA-Z_]\w*[\(|:]/gm)
 
-            if(!classes) {
-                application.add_error("Can't find any index class in your code.")
-                return
+                    if(!classes) {
+                        application.add_error("Can't find any index class in your code.")
+                            return
+                    }
+
+                // ['class Klass(', ['class Klass2:']] => ['Klass', 'Klass2']
+                for (var i = 0; i < classes.length; i++) classes[i] = classes[i].split(' ')[1].slice(0, -1)
+                    classes = ko.utils.arrayGetDistinctValues(classes)
+                        self.class_names(classes)
+                        self.class_name(classes[0])
+
+                $("#save_plain_modal").modal('show')
+            } else {
+                self._create()
             }
-
-            // ['class Klass(', ['class Klass2:']] => ['Klass', 'Klass2']
-            for (var i = 0; i < classes.length; i++) classes[i] = classes[i].split(' ')[1].slice(0, -1)
-            classes = ko.utils.arrayGetDistinctValues(classes)
-            self.class_names(classes)
-            self.class_name(classes[0])
-
-            $("#save_plain_modal").modal('show')
         }
 
 
         self.open_save_edit_modal = function() {
-            // look for classes in index code
-            var classes = self.index_code().match(/^class\s+[a-zA-Z_]\w*[\(|:]/gm)
+            if (self.is_normal_code()) {
+                // look for classes in index code
+                var classes = self.index_code().match(/^class\s+[a-zA-Z_]\w*[\(|:]/gm)
 
-            if(!classes) {
-                application.add_error("Can't find any index class in your code.")
-                return
+                    if(!classes) {
+                        application.add_error("Can't find any index class in your code.")
+                            return
+                    }
+
+                // ['class Klass(', ['class Klass2:']] => ['Klass', 'Klass2']
+                for (var i = 0; i < classes.length; i++) classes[i] = classes[i].split(' ')[1].slice(0, -1)
+                    classes = ko.utils.arrayGetDistinctValues(classes)
+                        self.class_names(classes)
+                        self.class_name(classes[0])
+
+                $("#save_edit_plain_modal").modal('show')
+            } else {
+                self._edit()
             }
+        }
 
-            // ['class Klass(', ['class Klass2:']] => ['Klass', 'Klass2']
-            for (var i = 0; i < classes.length; i++) classes[i] = classes[i].split(' ')[1].slice(0, -1)
-            classes = ko.utils.arrayGetDistinctValues(classes)
-            self.class_names(classes)
-            self.class_name(classes[0])
-
-            $("#save_edit_plain_modal").modal('show')
+        self.switch_new_code = function () {
+            if (self.is_normal_code()) {
+                self.python_code = self.index_code()
+                self.index_code(self.simplified_code)
+            } else {
+                self.simplified_code = self.index_code()
+                self.index_code(self.python_code)
+            }
+            self.is_normal_code(!self.is_normal_code())
         }
 
         self.save = function() {
 
             var code_header = "# " + self.form_name() + "\n"
             code_header += "# " + self.class_name() + '\n'
-            code_header += header_footer + "\n\n"
+            code_header += header_footer + "\n"
             var code = ''
-
             if(self.index_code().split('\n')[2].indexOf(header_footer) == 0)
                 code = self.index_code().split('\n').splice(4).join('\n')
             else
         self.insert_plain = function(){
             $.get('/get_index_header')
             .success(function(data) {
+                    /*console.log(data)*/
                 lines = data.split('\n')
+                /*console.log(self.index_code())*/
                 self.index_code(lines.slice(3).join('\n'))
             })
         }
             }
         })
 
+        self.is_normal_code.subscribe(function(newValue){
+            if(my_cms['index_code']){
+                my_cms['index_code'].setOption('mode',self.is_normal_code() ? 'python' : 'text')
+            }
+        })
+        
         self.get_index_code = function() {
-            $.get('/get_index_code/' + self.name, {},
-                function(data) {
+            $.get('/get_index_code/' + self.name ,{code_switch : JSON.stringify("S")}, function(data) {
+                if(!self.is_normal_code()){
                     self.index_code(data)
-                    if(application.index_changed != null) {
-                        $('button.btn-reindex').popover({"placement": "top", title: application.index_changed}).popover('show')
-                        application.index_changed = null
-                    }
                 }
-            )
+                self.simplified_code = data
+                })
+            $.get('/get_index_code/' + self.name,{code_switch : JSON.stringify("P")}, function(data) {
+                if (self.is_normal_code()){
+                    self.index_code(data)
+                }
+                self.python_code = data
+                })
+
+            if(application.index_changed != null) {
+                $('button.btn-reindex').popover({"placement": "top", title: application.index_changed}).popover('show')
+                application.index_changed = null
+            }
         }
 
         self.get_index_template = function() {
                 self.show_code(!self.show_code())
                 if(!self.show_code()) {
                     self.get_details()
+                } else { // XXX: fix it
+                    setTimeout(function() {
+                        my_cms['index_code'].setOption('mode',self.is_normal_code() ? 'python' : 'text')}, 0)
                 }
             }
         }
+        
+
+        self.switch_code = function () {
+            if (self.is_normal_code()) {
+                $.get('/get_index_code/' + self.name ,{code_switch : JSON.stringify("S")}, function(data) {
+                    self.simplified_code = data 
+                    self.index_code(data)
+                    })
+            } else {
+                $.get('/get_index_code/' + self.name ,{code_switch : JSON.stringify("P")}, function(data) {
+                    self.python_code = data 
+                    self.index_code(data)
+                    })
+            }
+            self.is_normal_code(!self.is_normal_code())
+        }
 
         self.code_details_text = function() {
             if (!self.show_code()) {
                 this.before({}, function() {
                     // Dropdown clearMenus() is not called when we using Sammy.js...
                     $('[data-toggle="dropdown"]').parent().removeClass('open')
+                    $('div.popover').remove()
                     self.has_indexes_names()
                     self.clean_iface()
                 })
     application = new DBViewModel()
 
     ko.applyBindings(application)
-})()
+})()

CodernityDBHTTP/interface/scripts/lib/notifier.js

+// https://github.com/Srirangan/notifer.js/
+// for author and details
+// this version is a bit changed for CodernityDB-HTTP needs
+
 (function($){
 
   var config = window.NotifierjsConfig = {
     Notifier.notify(message, title, "data:image/png;base64,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%3D");
   };
   Notifier.error = function(message, title) {
-    Notifier.notify(message, title, "data:image/png;base64,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%3D%3D");
+      title = title ? title : 'An error occurred';
+      $('#notifier h3').html(title);
+      $('#notifier pre').html(message);
+      $('#notifier').modal('show');
   };
   Notifier.success = function(message, title) {
     Notifier.notify(message, title, "data:image/png;base64,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%3D");

CodernityDBHTTP/misc.py

 from os import path as os_path
 from os import access as os_access
 from os import R_OK
+from os import stat
 import sys
 from all_exceptions import DBHTTPException, HTTPDatabaseException, HTTPNotFoundException, HTTPConflictException, DBIsNotOpened
 from types import FunctionType, MethodType, GeneratorType
 from CodernityDB.database import RevConflict, RecordDeleted, RecordNotFound
 import httplib
 
+try:
+    import ujson as json
+except ImportError:
+    try:
+        import simplejson as json
+    except ImportError:
+        try:
+            import json
+        except ImportError:
+            # rly ?
+            has_json = False
+    else:
+        has_json = True
+else:
+    has_json = True
 
 import traceback
 
     'DatabasePathException': 409,
     'DatabaseIsNotOpened': 409,
     'TryReindexException': 409,
-    'ReindexException': 409
+    'ReindexException': 409,
+    'IndexCreatorValueException': 400,
+    'IndexCreatorFunctionException': 400
 }
 
 
                     '.', 1)[1], content_types['default'])
             except:
                 content_type = content_types['default']
+            f_size = stat(f_path).st_size
             with open(f_path, 'rb') as fp:
-                start_response("200 OK", [('Content-Type', content_type)])
+                start_response("200 OK", [('Content-Type', content_type),
+                                          ('Content-Length', str(f_size)),
+                                          ('Content-Encoding', 'chunked')])
                 chunk = fp.read(4096)
                 while chunk:
                     yield chunk
     else:
         error = "%s %s" % (500, httplib.responses[500])
         with_traceback = True
+
     exception_output = {'exception': exc_type.__name__,
                         'reason': reason,
-                        'error': error}
+                        'error': error
+                        }
     if with_traceback:
+
+
+def open_with_autosave(db, cfg_path, cfg):
+    def _inner(*args, **kwargs):
+        db.open(*args, **kwargs)
+        if cfg.get('auto_save') and cfg.get('db_path') != db.path:
+            cfg['db_path'] = db.path
+            with open(cfg_path, 'w') as f:
+                f.write(json.dumps(cfg, sort_keys=True, indent=4))
+    return _inner
         tb = traceback.format_exception(exc_type, exc_value, exc_traceback)
         exception_output['traceback'] = ''.join(tb)
         sys.stderr.writelines(tb)  # print the traceback to console

CodernityDBHTTP/server.py

         from server_wsgiref import create_server
     else:
         raise NotImplemented("Not supported server method")
-    s = create_server(bind, port, db_path, cfg)
+    s = create_server(bind, port, db_path, cfg, path)
     del create_server
     cfg['port'] = s.server_port
     return s, cfg

CodernityDBHTTP/server_gevent.py

         super(CodernityDBGeventWSGIServer, self).__init__(*args, **kwargs)
 
 
-def create_server(bind, port, db_path, cfg, **kwargs):
+def create_server(bind, port, db_path, cfg, cfg_path, **kwargs):
     from gevent import socket
     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
     backlog = kwargs.get('backlog', 50)
     sock.listen(backlog)
     s = CodernityDBGeventWSGIServer(
-        sock, get_app(HTTPGeventDatabase, db_path, cfg))
+        sock, get_app(HTTPGeventDatabase, db_path, cfg, cfg_path))
     return s

CodernityDBHTTP/server_wsgiref.py

 
 #         #self.base_env['SERVER_SOFTWARE'] = 'CodernityDB(%s) @ wsgiref' % __db__version__
 
-def create_server(bind, port, db_path, cfg, **kwargs):
-    app = get_app(HTTPThreadSafeDatabase, db_path, cfg)
+def create_server(bind, port, db_path, cfg, cfg_path, **kwargs):
+    app = get_app(HTTPThreadSafeDatabase, db_path, cfg, cfg_path)
     s = make_server(bind, port, app)
     return s