From e2b95cefd1e34e652317fdf82595932c0bf0c6bb Mon Sep 17 00:00:00 2001 From: Chris Jaekl Date: Mon, 20 Nov 2017 21:36:24 +0900 Subject: [PATCH] Adds config file (quanlib.ini) support. Also adds a test for browser compatibility, and display an error message if the user is using an unsupported browser (likely suspects are IE11 and Android Browser 4.x). --- THIRD_PARTY | 29 ++++++++++ app/index.html | 7 ++- app/modernizr-custom.js | 3 + js/BooksModel.js | 7 +-- js/Main.js | 14 ++++- js/SearchController.js | 6 +- main/config.go | 122 ++++++++++++++++++++++++++++++++++++++-- main/db.go | 2 +- main/handler.go | 4 +- main/main.go | 4 +- 10 files changed, 178 insertions(+), 20 deletions(-) create mode 100644 THIRD_PARTY create mode 100644 app/modernizr-custom.js diff --git a/THIRD_PARTY b/THIRD_PARTY new file mode 100644 index 0000000..e61916e --- /dev/null +++ b/THIRD_PARTY @@ -0,0 +1,29 @@ +=========================================================================== +Other terms and conditions +=========================================================================== + +Portions of this software (libraries) were developed by other people, +and are subject to the licence terms that those people chose. + +--------------------------------------------------------------------------- +Modernizr + +This JavaScript library, available at https://modernizr.com/, +is distributed under the MIT licence: + + Copyright © 2009-2017 + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. diff --git a/app/index.html b/app/index.html index 26a0374..d417fef 100644 --- a/app/index.html +++ b/app/index.html @@ -1,4 +1,4 @@ - + eBook Library @@ -6,7 +6,7 @@ - +
Author: @@ -25,6 +25,7 @@
(No information available)
- + + diff --git a/app/modernizr-custom.js b/app/modernizr-custom.js new file mode 100644 index 0000000..9fdeb1c --- /dev/null +++ b/app/modernizr-custom.js @@ -0,0 +1,3 @@ +/*! modernizr 3.5.0 (Custom Build) | MIT * + * https://modernizr.com/download/?-fetch-setclasses !*/ +!function(n,e,s){ function o(n,e){ return typeof n===e; } function a(){ var n,e,s,a,t,l,r; for(var c in f) if(f.hasOwnProperty(c)) { if(n=[],e=f[c],e.name && (n.push(e.name.toLowerCase()),e.options && e.options.aliases && e.options.aliases.length)) for(s=0;s response.json()) - .then((jsonValue) => { - console.log('JSON response for info: ', jsonValue); + .then(function(response) {return response.json();}) + .then(function(jsonValue) { my.cache = jsonValue; notifyAll(); // inform all subscribers that the model has been updated }) - .catch(err => { + .catch(function(err) { var msg = 'Error fetching book details via URL: ' + url + ': ' + err; console.log(msg, err.stack); report(msg); diff --git a/js/Main.js b/js/Main.js index 6ceac82..5f253bc 100644 --- a/js/Main.js +++ b/js/Main.js @@ -1,5 +1,5 @@ -//QuanLib: eBook Library -//(C) 2017 by Christian Jaekl (cejaekl@yahoo.com) +// QuanLib: eBook Library +// Copyright (C) 2017 by Christian Jaekl (cejaekl@yahoo.com) 'use strict'; @@ -20,6 +20,16 @@ BooksView.init(BooksModel); PagingController.init(BooksModel); SearchController.init(BooksModel); +if (Modernizr.fetch) { + console.log('quanweb: browser feature check: OK'); +} +else { + // If we cared about supporting older browsers (at this point, IE11 and Adroid 4.x's built-in browser, + // neither of which is due to receive security patch support for much longer), then we would insert a + // shim here to implement the fetch API. But, in this case, we don't and won't. + alert('Sorry, this page will not work in your browser.\nPlease use a recent version of Chrome, Edge or Firefox instead.'); +} + // ================ // Global functions // diff --git a/js/SearchController.js b/js/SearchController.js index 5b770b5..b95c951 100644 --- a/js/SearchController.js +++ b/js/SearchController.js @@ -22,8 +22,8 @@ var SearchController = (function () { var url = constructSearchUrl(); fetch(url, {method:'GET', cache:'default'}) - .then(response => response.json()) - .then((jsonValue) => { + .then(function(response) {return response.json();}) + .then(function(jsonValue) { // console.log('JSON response: ', jsonValue); booksModel.ids = jsonValue; booksModel.count = booksModel.ids.length; @@ -34,7 +34,7 @@ var SearchController = (function () { PagingController.adjustPos(0); }) - .catch(err => { + .catch(function(err) { var msg = 'Error fetching JSON from URL: ' + url + ': ' + err + ':' + err.stack; console.log(msg); report(msg); diff --git a/main/config.go b/main/config.go index 3d0a6cf..64ae010 100644 --- a/main/config.go +++ b/main/config.go @@ -1,10 +1,124 @@ package main +import ( + "errors" + "fmt" + "github.com/alyu/configparser" + "os" + "strconv" +) + type qwConfig struct { - user, pass, dbName, efsBasePath string + user, pass, dbName string + basePath string + port int +} + +func checkedSection(config *configparser.Configuration, name string) (*configparser.Section, error) { + section, err := config.Section(name) + if nil != err { + fmt.Println("ERROR! Could not locate section [" + name + "] in config file:", err) + return nil, err + } + return section, nil +} + +func checkedValue(section *configparser.Section, name string) (string, error) { + if ! section.Exists(name) { + return "", errors.New("ERROR! Value named \"" + name + "\" not found in config file.") + } + + value := section.ValueOf(name) + return value, nil +} + +// Note: Will exit if config cannot be loaded +func GetConfig() (*qwConfig) { + config, err := loadConfig() + if nil != err { + fmt.Println("FATAL! Cannot load config. Unable to continue.", err) + os.Exit(1) + } + + return config } -func getConfig() qwConfig { - // TODO: use a real password, and load config info from a file - return qwConfig{user:"quanlib", pass:"quanlib", dbName:"quanlib", efsBasePath:"/arc/quanlib/efs"} +func loadConfig() (*qwConfig, error) { + // TODO: Make the path to the config file configurable (environment variable?) + // TODO: Load the config file once, and cache the values for subsequent getConfig() calls + + const configFile = "quanlib.ini" + + config, err := configparser.Read(configFile) + if nil != err { + fmt.Println("ERROR! Failed to read config file:", configFile, err) + return nil, err + } + + var section *configparser.Section + + // ------------------ + // Section: database + + var dbName, user, pass string + + section, err = checkedSection(config, "database") + if nil != err { + return nil, err + } + + dbName, err = checkedValue(section, "name") + if nil != err { + return nil, err + } + + user, err = checkedValue(section, "user") + if nil != err { + return nil, err + } + + pass, err = checkedValue(section, "pass") + if nil != err { + return nil, err + } + + // -------------------- + // Section: filesystem + + var basePath string + + section, err = checkedSection(config, "filesystem") + if nil != err { + return nil, err + } + + basePath, err = checkedValue(section, "basePath") + if nil != err { + return nil, err + } + + // ------------- + // Section: web + + var port int + var portStr string + + section, err = checkedSection(config, "web") + if nil != err { + return nil, err + } + + portStr, err = checkedValue(section, "port") + if nil != err { + return nil, err + } + port, err = strconv.Atoi(portStr) + if nil != err { + return nil, err + } + + return &qwConfig{ user:user, pass:pass, dbName:dbName, + basePath:basePath, + port:port }, + nil } diff --git a/main/db.go b/main/db.go index 53c0a2c..809634a 100644 --- a/main/db.go +++ b/main/db.go @@ -57,7 +57,7 @@ func getDb() (*sql.DB) { g_mutex.Lock() defer g_mutex.Unlock() if nil == g_db { - config := getConfig() + config := GetConfig() g_db = openDb(config.user, config.pass, config.dbName) } } diff --git a/main/handler.go b/main/handler.go index 2d8076e..cd35a76 100644 --- a/main/handler.go +++ b/main/handler.go @@ -29,10 +29,10 @@ func bookMimeType(bookPath string) string { } func efsPathForId(efsId int) string { - config := getConfig() + config := GetConfig() idStr := fmt.Sprintf("%010d", efsId) - path := fmt.Sprintf("%s/%s/%s/%s/%s/%s.dat", config.efsBasePath, idStr[0:2], idStr[2:4], idStr[4:6], idStr[6:8], idStr) + path := fmt.Sprintf("%s/efs/%s/%s/%s/%s/%s.dat", config.basePath, idStr[0:2], idStr[2:4], idStr[4:6], idStr[6:8], idStr) return path } diff --git a/main/main.go b/main/main.go index d30f84b..b54712f 100644 --- a/main/main.go +++ b/main/main.go @@ -3,6 +3,7 @@ package main import ( "database/sql" "net/http" + "strconv" ) // ============================================================================ @@ -17,5 +18,6 @@ func main() { http.HandleFunc("/", handler) - http.ListenAndServe(":8001", nil) + config := GetConfig() + http.ListenAndServe(":" + strconv.Itoa(config.port), nil) } -- 2.39.2