github.com/mmatczuk/gohan@v0.0.0-20170206152520-30e45d9bdb69/extension/otto/gohan_core.go (about) 1 // Copyright (C) 2015 NTT Innovation Institute, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 // implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package otto 17 18 import ( 19 "io/ioutil" 20 "strings" 21 "fmt" 22 "os" 23 24 "github.com/ddliu/motto" 25 26 "github.com/cloudwan/gohan/schema" 27 "github.com/robertkrimen/otto" 28 l "github.com/cloudwan/gohan/log" 29 "github.com/cloudwan/gohan/util" 30 ) 31 32 var log = l.NewLogger() 33 34 func init() { 35 gohanInit := func(env *Environment) { 36 vm := env.VM 37 builtins := map[string]interface{}{ 38 "require": func(call otto.FunctionCall) otto.Value { 39 VerifyCallArguments(&call, "require", 1) 40 moduleName, err := GetString(call.Argument(0)) 41 if err != nil { 42 ThrowOttoException(&call, err.Error()) 43 } 44 value, err := require(moduleName, vm) 45 if err != nil { 46 ThrowOttoException(&call, err.Error()) 47 } 48 return value 49 }, 50 "gohan_schemas": func(call otto.FunctionCall) otto.Value { 51 VerifyCallArguments(&call, "gohan_schemas", 0) 52 manager := schema.GetManager() 53 response := []interface{}{} 54 for _, schema := range manager.OrderedSchemas() { 55 response = append(response, schema) 56 } 57 value, _ := vm.ToValue(response) 58 return value 59 }, 60 "gohan_schema_url": func(call otto.FunctionCall) otto.Value { 61 VerifyCallArguments(&call, "gohan_schema_url", 1) 62 schemaID, err := GetString(call.Argument(0)) 63 if err != nil { 64 ThrowOttoException(&call, err.Error()) 65 } 66 manager := schema.GetManager() 67 schema, ok := manager.Schema(schemaID) 68 if !ok { 69 ThrowOttoException(&call, unknownSchemaErrorMesssageFormat, schemaID) 70 } 71 value, _ := vm.ToValue(schema.URL) 72 return value 73 }, 74 "gohan_policies": func(call otto.FunctionCall) otto.Value { 75 VerifyCallArguments(&call, "gohan_policies", 0) 76 manager := schema.GetManager() 77 response := []interface{}{} 78 for _, policy := range manager.Policies() { 79 response = append(response, policy.RawData) 80 } 81 value, _ := vm.ToValue(response) 82 return value 83 }, 84 } 85 86 for name, object := range builtins { 87 vm.Set(name, object) 88 } 89 90 loadNPMModules() 91 92 err := env.Load("<Gohan built-in exceptions>", ` 93 function BaseException() { 94 this.fields = ["name", "message"] 95 this.message = ""; 96 this.name = "BaseException"; 97 98 this.toDict = function () { 99 return _.reduce(this.fields, function(resp, field) { 100 resp[field] = this[field]; 101 return resp; 102 }, {}, this); 103 }; 104 105 this.toString = function () { 106 return this.name.concat("(").concat(this.message).concat(")"); 107 }; 108 } 109 110 function CustomException(msg, code) { 111 BaseException.call(this); 112 this.message = msg; 113 this.name = "CustomException"; 114 this.code = code; 115 this.fields.push("code"); 116 } 117 CustomException.prototype = Object.create(BaseException.prototype); 118 119 function ResourceException(msg, problem) { 120 BaseException.call(this); 121 this.message = msg; 122 this.name = "ResourceException"; 123 this.problem = problem; 124 this.fields.push("problem"); 125 } 126 ResourceException.prototype = Object.create(BaseException.prototype); 127 128 function ExtensionException(msg, inner_exception) { 129 BaseException.call(this); 130 this.message = msg; 131 this.name = "ExtensionException"; 132 this.inner_exception = inner_exception; 133 this.fields.push("inner_exception"); 134 } 135 ExtensionException.prototype = Object.create(BaseException.prototype); 136 `) 137 if err != nil { 138 log.Fatal(err) 139 } 140 141 err = env.Load("<Gohan built-ins>", ` 142 var gohan_handler = {} 143 function gohan_register_handler(event_type, func){ 144 if(_.isUndefined(gohan_handler[event_type])){ 145 gohan_handler[event_type] = []; 146 } 147 gohan_handler[event_type].push(func) 148 } 149 150 function gohan_handle_event(event_type, context){ 151 if(_.isUndefined(gohan_handler[event_type])){ 152 return; 153 } 154 155 for (var i = 0; i < gohan_handler[event_type].length; ++i) { 156 try { 157 var old_module = gohan_log_module_push(event_type); 158 gohan_handler[event_type][i](context); 159 //backwards compatibility 160 if (!_.isUndefined(context.response_code)) { 161 throw new CustomException(context.response, context.response_code); 162 } 163 } catch(e) { 164 if (e instanceof BaseException) { 165 context.exception = e.toDict(); 166 context.exception_message = event_type.concat(": ").concat(e.toString()); 167 } else { 168 throw e; 169 } 170 } finally { 171 gohan_log_module_restore(old_module); 172 } 173 } 174 } 175 `) 176 if err != nil { 177 log.Fatal(err) 178 } 179 } 180 RegisterInit(gohanInit) 181 } 182 183 func requireFromOtto(moduleName string, vm *otto.Otto) (otto.Value, error) { 184 log.Debug(fmt.Sprintf("Loading module %s from otto", moduleName)) 185 rawModule, errRequire := RequireModule(moduleName) 186 if errRequire != nil { 187 return otto.UndefinedValue(), errRequire 188 } 189 190 module, errConvert := vm.ToValue(rawModule) 191 if errConvert != nil { 192 return otto.UndefinedValue(), errConvert 193 } 194 195 return module, nil 196 } 197 198 func requireFromMotto(moduleName string, vm *motto.Motto) (otto.Value, error) { 199 log.Debug(fmt.Sprintf("Loading module %s from motto", moduleName)) 200 v, err := vm.Require(moduleName, "") 201 if err != nil { 202 log.Error("Cannot load module %s in Motto, err:%s", moduleName, err.Error()) 203 } 204 return v, err 205 } 206 207 func require(moduleName string, vm *motto.Motto) (otto.Value, error) { 208 value, err := requireFromMotto(moduleName, vm) // NPM 209 if err != nil { 210 log.Error(fmt.Sprintf("Loading module %s from motto failed: %s, trying to load from otto", 211 moduleName, err)) 212 value, err = requireFromOtto(moduleName, vm.Otto) // Go extensions 213 } 214 215 return value, err 216 } 217 218 func loadNPMModules() { 219 config := util.GetConfig() 220 npmPath := config.GetString("extension/npm_path", ".") 221 files, _ := ioutil.ReadDir(npmPath + "/node_modules/") 222 for _, f := range files { 223 if f.IsDir() && !strings.HasPrefix(f.Name(), ".") { 224 module, err := motto.FindFileModule(f.Name(), npmPath, nil) 225 if err != nil { 226 log.Error("Finding module failed %s in %s", err, f.Name()) 227 break 228 } 229 230 var entryPoint string 231 entryPointCandidates := []string {module, module + ".js", module + "/index.js"} 232 233 for _, candidate := range entryPointCandidates { 234 if candidateFile, err := os.Stat(candidate); err == nil && !candidateFile.IsDir() { 235 entryPoint = candidate 236 break 237 } 238 } 239 240 if entryPoint == "" { 241 log.Error("Cannot find entry point of %s module", module) 242 break 243 } 244 245 loader := motto.CreateLoaderFromFile(entryPoint) 246 motto.AddModule(f.Name(), loader) 247 } 248 } 249 }