public void Register(PluginInfo pluginInfo) { try { if (pluginInfo.Type != PluginType.BackgroundThread) { throw new ArgumentException("Plugin must be a BackgroundThread type", nameof(pluginInfo)); } var existing = _registrations.FirstOrDefault(r => r.PluginGuid.Equals(pluginInfo.Guid.ToString(), StringComparison.OrdinalIgnoreCase)); if (existing == null) { existing = BackgroundThreadPluginRegistration.Create(pluginInfo); _registrations.Add(existing); } existing.CreateEndpointInstances(_hubContext); var list = Hubs.BackgroundPluginHub.BgPluginsList(); _hubContext.Clients.Group(Hubs.BackgroundPluginHub.ADMIN_GROUP_NAME).SendAsync("updateList", list); } catch (Exception ex) { SessionLog.Error($"Failed to instantiate plugin '{pluginInfo.Name}' ({pluginInfo.Guid}) from assembly {pluginInfo.Assembly.FullName}. See exception that follows."); SessionLog.Exception(ex); } }
private static void ProcessPluginExecutionExceptionHandlers(List <ExecutionPlugin> pluginList, SqlConnection con, Exception ex, string additionalInfo, string appTitle, string appVersion, out string externalRef) { externalRef = null; if (pluginList == null) { return; } foreach (var plugin in pluginList) { try { string msg = null; string externalRefTmp = null; plugin.OnExecutionException(con, ex, additionalInfo, appTitle, appVersion, out externalRefTmp, out msg); if (!string.IsNullOrWhiteSpace(externalRefTmp)) { externalRef = externalRefTmp; } } catch (Exception e) { SessionLog.Error("Plugin {0} OnExecutionException failed", plugin.Name); SessionLog.Exception(e); } } }
// called after Endpoint is deserialized from the Settings json public async void AfterDeserializationInit() { if (!string.IsNullOrEmpty(this.PullMetadataFromEndpointId)) { var srcEndPoint = Settings.SettingsInstance.Instance.FindEndpointById(this.PullMetadataFromEndpointId); if (srcEndPoint != null) { var cachedRoutineList = await srcEndPoint._cachedRoutinesPromise.Task; this.CachedRoutineList = cachedRoutineList; } else { SessionLog.Error($"Endpoint {this.Pedigree} is configured to pull metadata from an endpoint with id {this.PullMetadataFromEndpointId} but that endpoint does not exist."); } } else { await this.LoadCacheAsync(); } if (this.ExecutionConnection != null) { this.ExecutionConnection.Endpoint = this; this.ExecutionConnection.Type = "execution"; } if (this.MetadataConnection != null) { this.MetadataConnection.Endpoint = this; this.MetadataConnection.Type = "metadata"; } }
public void Start() { if (_counterMonitor != null) { return; } _counterMonitor = new CounterMonitor(_pid, GetProviders()); _counterMonitor.CounterUpdate += OnCounterUpdate; Task monitorTask = new Task(() => { try { _counterMonitor.Start(); } catch (Exception x) { SessionLog.Error("DotNet Counter failure"); SessionLog.Exception(x); // Environment.FailFast("Error while listening to counters", x); } }); monitorTask.Start(); }
public Connection GetSqlConnection() { if (this.ExecutionConnection == null) { SessionLog.Error($"Execution connection not found on endpoint '{this.Name}'({ this.Id })."); } return(this.ExecutionConnection); }
public async Task <IActionResult> ScanPdf417(string blobRef, [FromQuery] bool?raw = false, [FromQuery] bool?veh = false, [FromQuery] bool?drv = false) { var res = this.Response; var req = this.Request; try { // always start off not caching whatever we send back res.Headers["Cache-Control"] = "no-cache, no-store, must-revalidate, max-age=0"; res.Headers["Pragma"] = "no-cache"; // HTTP 1.0. res.Headers["Content-Type"] = "application/json"; if (!BlobStore.Exists(blobRef)) { return(NotFound($"Invalid, non-existent or expired blob reference specified: '{blobRef}'")); } var blobData = BlobStore.Get(blobRef); var client = new System.Net.Http.HttpClient(); using (var content = new System.Net.Http.ByteArrayContent(blobData.Data)) { var barcodeServiceUrl = this.config["AppSettings:BarcodeService.URL"].TrimEnd('/'); var postUrl = $"{barcodeServiceUrl}/scan/pdf417?raw={raw}&veh={veh}&drv={drv}"; var response = await client.PostAsync(postUrl, content); var responseText = await response.Content.ReadAsStringAsync(); if (response.StatusCode == System.Net.HttpStatusCode.OK) { var json = JsonConvert.DeserializeObject(responseText); return(Ok(ApiResponse.Payload(json))); } else { SessionLog.Error("Barcode failed. postUrl = {0}; contentLength: {1}; responseText={2}", postUrl ?? "(null)", blobData?.Data?.Length ?? -1, responseText ?? "(null)"); //return StatusCode((int)response.StatusCode, responseText); //return new ContentResult() { Content = responseText, StatusCode = (int)response.StatusCode, ContentType = "text/plain" }; return(BadRequest(responseText)); } } } catch (Exception ex) { return(Ok(ApiResponse.Exception(ex))); } }
private void ProcessMessagesLoop() { try { IsRunning = true; var nextFlush = DateTime.Now.AddSeconds(_flushTimeoutInSeconds); if (!string.IsNullOrWhiteSpace(_threadName)) { System.Threading.Thread.CurrentThread.Name = _threadName; } while (IsRunning && !Program.IsShuttingDown) { // timeout or count trigger check if (DateTime.Now >= nextFlush || _queue.Count >= _flushCountThreshold) { ProcessQueueUntilEmpty(); nextFlush = DateTime.Now.AddSeconds(_flushTimeoutInSeconds); } // perform any additional work that might be required DoWork(); Thread.Sleep(60); } // flush any remaining items out ProcessQueueUntilEmpty(); DoFinalWork(); } catch (Exception ex) { Log.Error(ex, "ProcessMessagesLoop failed"); ExceptionLogger.LogException(ex); SessionLog.Error("ProcessMessagesLoop failed"); SessionLog.Exception(ex); } finally { IsRunning = false; } }
public void BuildAndCacheServerMethodJsAndTSD() { try { var registrations = ServerMethodManager.GetRegistrationsForApp(this); if (registrations.Count() > 0) { this.GenerateX(registrations); } else { this.ServerMethodJs = this.ServerMethodTSD = this.ServerMethodJsEtag = this.ServerMethodTSDEtag = null; } } catch (Exception ex) { SessionLog.Error($"Failed to generate ServerMethod output files for {this.Project.Name}/{this.Name}.See exception that follows."); SessionLog.Exception(ex); } }
public static void Register(string pluginAssemblyInstanceId, PluginInfo pluginInfo) { try { var reg = ServerMethodPluginRegistration.Create(pluginAssemblyInstanceId, pluginInfo); lock (GlobalRegistrations) { if (!GlobalRegistrations.ContainsKey(pluginAssemblyInstanceId)) { GlobalRegistrations.Add(pluginAssemblyInstanceId, new List <ServerMethodPluginRegistration>()); } GlobalRegistrations[pluginAssemblyInstanceId].Add(reg); } } catch (Exception ex) { SessionLog.Error($"Failed to instantiate plugin '{pluginInfo.Name}' ({pluginInfo.Guid}) from assembly {pluginInfo.Assembly.FullName}. See exception that follows."); SessionLog.Exception(ex); } }
// TODO: Consider reworking this - ExecPlugins should only get instantiated once?! The assembly is instantiated once so maybe creating new instances of the plugin class is not that bad? private static List <ExecutionPlugin> InitPlugins(Application app, Dictionary <string, string> queryString, Dictionary <string, string> requestHeaders) { var concretePlugins = new List <ExecutionPlugin>(); if (PluginLoader.Instance.PluginAssemblies != null && app.Plugins != null) { foreach (string pluginGuid in app.Plugins) { var plugin = PluginLoader.Instance .PluginAssemblies .SelectMany(a => a.Plugins) .Where(p => p.Type == PluginType.Execution) .FirstOrDefault(p => p.Guid.ToString().Equals(pluginGuid, StringComparison.OrdinalIgnoreCase)); if (plugin != null) { try { var concrete = (ExecutionPlugin)plugin.Assembly.CreateInstance(plugin.TypeInfo.FullName); initPluginMethod.Invoke(concrete, new object[] { queryString, requestHeaders }); concretePlugins.Add(concrete); } catch (Exception ex) { SessionLog.Error("Failed to instantiate '{0}' ({1}) on assembly '{2}'", plugin.TypeInfo.FullName, pluginGuid, plugin.Assembly.FullName); SessionLog.Exception(ex); ExceptionLogger.LogExceptionThrottled(ex, "ExecController::InitPlugins", 2); } } } } return(concretePlugins); }
public static void ProcessMessagesLoop() { try { IsRunning = true; var flushTimeoutInSeconds = 25; var checkpointTimeoutInSeconds = 3 * 60; var nextFlush = DateTime.Now.AddSeconds(flushTimeoutInSeconds); var nextCheckpoint = DateTime.Now.AddSeconds(checkpointTimeoutInSeconds); System.Threading.Thread.CurrentThread.Name = "Stats DB"; while (IsRunning && !Program.IsShuttingDown) { // timeout or count trigger check if (DateTime.Now >= nextFlush || _executionQueue.Count >= 100) { while (!_executionQueue.IsEmpty) { if (_executionQueue.TryDequeue(out var statsRoutineExecution)) { InsertUpdate(statsRoutineExecution); } } nextFlush = DateTime.Now.AddSeconds(flushTimeoutInSeconds); } // checkpoint if (DateTime.Now >= nextCheckpoint) { _database.Checkpoint(); nextCheckpoint = DateTime.Now.AddSeconds(checkpointTimeoutInSeconds); } Thread.Sleep(60); } // flush any remaining items out while (!_executionQueue.IsEmpty) { if (_executionQueue.TryDequeue(out var statsRoutineExecution)) { InsertUpdate(statsRoutineExecution); } } } catch (Exception ex) { Log.Error(ex, "StatsDB::ProcessMessagesLoop failed"); SessionLog.Error("StatsDB::ProcessMessagesLoop failed"); SessionLog.Exception(ex); } finally { IsRunning = false; } }
public (plugin.ServerMethodPlugin, ServerMethodRegistrationMethod /*matched Method*/, string /*error*/) GetServerMethodPluginInstance(string nameSpace, string methodName, Dictionary <string, string> inputParameters) { // find all registered ServerMethods for this app var registrations = ServerMethodManager.GetRegistrationsForApp(this.Application); // TODO: To support overloading we need to match name + best fit parameter list var methodCandidates = registrations.SelectMany(reg => reg.Methods) .Where(m => ((nameSpace == null && m.Namespace == null) || (m.Namespace?.Equals(nameSpace, StringComparison.Ordinal) ?? false)) && m.Name.Equals(methodName, StringComparison.Ordinal)) .Select(m => m); if (methodCandidates.Count() == 0) { return(null, null, "Method name not found."); } var weightedMethodList = new List <(decimal /*weight*/, string /*error*/, ServerMethodRegistrationMethod)>(); // find the best matching overload (if any) foreach (var regMethod in methodCandidates) { var methodParameters = regMethod.AssemblyMethodInfo.GetParameters(); if (inputParameters.Count > methodParameters.Length) { weightedMethodList.Add((1M, "Too many parameters specified", regMethod)); continue; } var joined = from methodParam in methodParameters join inputParam in inputParameters on methodParam.Name equals inputParam.Key into grp from parm in grp.DefaultIfEmpty() select new { HasMatch = parm.Key != null, Param = methodParam }; var matched = joined.Where(e => e.HasMatch); var notmatched = joined.Where(e => !e.HasMatch); var expectedCnt = methodParameters.Count(); var matchedCnt = matched.Count(); // out/ref/optional parameters are added as extra credit below (but does not contribute to actual weight) var outRefSum = (from p in joined where (p.Param.IsOut || p.Param.IsOptional || p.Param.ParameterType.IsByRef) && !p.HasMatch select 1.0M).Sum(); if (matchedCnt == expectedCnt || matchedCnt + outRefSum == expectedCnt) { weightedMethodList.Add((matchedCnt, null, regMethod)); } else { //weightedMethodList.Add((matchedCnt, $"Following parameters not specified: {string.Join("\r\n", notmatched.Select(nm => nm.Param.Name))}", regMethod)); weightedMethodList.Add((matchedCnt, "Parameter mismatch", regMethod)); } } var bestMatch = weightedMethodList.OrderByDescending(k => k.Item1).FirstOrDefault(); if (!string.IsNullOrWhiteSpace(bestMatch.Item2)) { var parms = bestMatch.Item3.AssemblyMethodInfo.GetParameters(); var parmDesc = "(no parameters)"; if (parms.Length > 0) { parmDesc = string.Join("\r\n", parms.Select(p => $"{p.Name} ({p.ParameterType.ToString()})")); // TODO: Provide "easy to read" description for type, e.g. nullabe Int32 can be something like 'int?' and 'List<string>' just 'string[]' } return(null, bestMatch.Item3, $"Failed to find suitable overload.\r\nError: {bestMatch.Item2}\r\nBest match requires parameters:\r\n{parmDesc}"); } var matchedRegMethod = bestMatch.Item3; var cacheKey = $"{matchedRegMethod.Registration.PluginAssemblyInstanceId}; {matchedRegMethod.Registration.TypeInfo.FullName}"; plugin.ServerMethodPlugin pluginInstance = null; lock (ServerMethodInstanceCache) { if (ServerMethodInstanceCache.ContainsKey(cacheKey)) { pluginInstance = ServerMethodInstanceCache[cacheKey]; } else // instantiate a new instance { try { pluginInstance = (plugin.ServerMethodPlugin)matchedRegMethod.Registration.Assembly.CreateInstance(matchedRegMethod.Registration.TypeInfo.FullName); var initMethod = typeof(plugin.ServerMethodPlugin).GetMethod("InitSM", BindingFlags.Instance | BindingFlags.NonPublic); if (initMethod != null) { initMethod.Invoke(pluginInstance, new object[] { new Func <SqlConnection>(() => { if (this.ExecutionConnection != null) { var con = new SqlConnection(this.ExecutionConnection.ConnectionStringDecrypted); con.Open(); return(con); } return(new SqlConnection()); }) }); } else { SessionLog.Warning($"Failed to find InitSM method on plugin {matchedRegMethod.Registration.TypeInfo.FullName} from assembly {matchedRegMethod.Registration.Assembly.FullName}. Make sure the correct version of the jsdal plugin is used and that you derive from the correct base class (should be ServerMethodPlugin)."); } var setGetServicesFuncMethod = typeof(plugin.PluginBase).GetMethod("SetGetServicesFunc", BindingFlags.Instance | BindingFlags.NonPublic); if (setGetServicesFuncMethod != null) { setGetServicesFuncMethod.Invoke(pluginInstance, new object[] { new Func <Type, plugin.PluginService>(serviceType => { if (serviceType == typeof(plugin.BlobStoreBase)) { return(BlobStore.Instance); } return(null); }) }); } ServerMethodManager.RegisterInstanceUse(this, matchedRegMethod); ServerMethodInstanceCache.Add(cacheKey, pluginInstance); } catch (Exception ex) { SessionLog.Error($"Failed to instantiate plugin {matchedRegMethod.Registration.TypeInfo.FullName} from assembly {matchedRegMethod.Registration.Assembly.FullName}. See exception that follows."); SessionLog.Exception(ex); } } } // lock return(pluginInstance, matchedRegMethod, null); }
public void Run() { try { IsRunning = true; System.Threading.Thread.CurrentThread.Name = "jsDALHealthMonitorThread thread"; var sw = new Stopwatch(); var dbCollection = _database.GetCollection <jsDALHealthDbEntry>($"HealthData"); dbCollection.EnsureIndex("Created", unique: false); while (IsRunning && !Program.IsShuttingDown) { if (!_nextCheck.HasValue || DateTime.Now >= _nextCheck.Value) { // var endpoints = Settings.SettingsInstance.Instance.ProjectList.SelectMany(p => p.Applications).SelectMany(a => a.Endpoints); // sw.Restart(); // var q = from ep in endpoints // select new EndpointStats() // { // Endpoint = ep.Pedigree, // CachedRoutinesCount = ep.CachedRoutines.Count, // CachedRoutinesSizeInBytes = CalculateEstSizeInBytes(ep.CachedRoutines) // }; // var endpointStats = q.ToList(); // sw.Stop(); var proc = Process.GetCurrentProcess(); var blobStats = BlobStore.Instance.GetStats(); var memInfo = GC.GetGCMemoryInfo(); var newEntry = new jsDALHealthDbEntry() { Created = DateTime.Now, // TimeToCalculateSizesInMS = sw.ElapsedMilliseconds, // WorkingSet64 = proc.WorkingSet64, //EndpointStats = endpointStats, HeapSizeMB = (double)memInfo.HeapSizeBytes / 1024.0 / 1024.0, BlobCnt = blobStats.TotalItemsInCache, BlobsBytesInCache = blobStats.TotalBytesInCache, PrivateMemorySize64 = proc.PrivateMemorySize64, ExceutionsInFlight = Controllers.ExecController.ExceutionsInFlight }; dbCollection.Insert(newEntry); // delete entries older than 5 days dbCollection.DeleteMany(x => x.Created.Value <= DateTime.Now.AddDays(-5)); _database.Checkpoint(); _nextCheck = DateTime.Now.AddSeconds(45); } Thread.Sleep(60); } } catch (Exception ex) { Log.Error(ex, "jsDALHealthMonitorThread failed"); ExceptionLogger.LogException(ex); SessionLog.Error("jsDALHealthMonitorThread failed"); SessionLog.Exception(ex); } finally { IsRunning = false; if (_database != null) { _database.Checkpoint(); _database.Dispose(); _database = null; } } }
public void CreateEndpointInstances(IHubContext <Hubs.BackgroundPluginHub> hub) { IHubClients hubClients = hub.Clients; // TODO: Need to look at EP Creation Event and EP stopped & deleted event. var apps = Settings.SettingsInstance.Instance .ProjectList .SelectMany(proj => proj.Applications) .Where(app => app.IsPluginIncluded(this.PluginGuid.ToString())); var endpointCollection = apps.SelectMany(app => app.Endpoints); // create a default instance just to read the Default Value collection var defaultInstance = (BackgroundThreadPlugin)this.Assembly.CreateInstance(this.TypeInfo.FullName); var defaultConfig = defaultInstance.GetDefaultConfig(); if (defaultConfig?.ContainsKey("IsEnabled") ?? false) { var defIsEnabled = defaultConfig["IsEnabled"]; // TODO: Convert to better typed class (e.g. true/false) // TODO: Match up with Endpoint config. EP Config needs to be persisted somewhere } // TODO: For each BG Plugin catalog the 'server methods' available. (do this once per assembly, not per EP as they are the same for all EPs) foreach (var endpoint in endpointCollection) { try { // TODO: Look for an existing instance on the EP // TODO: If no longer ENABLED on EP kill instance? Won't currently be in collection above var existingInstance = FindPluginInstance(endpoint); if (existingInstance != null) { // no need to instantiate again continue; } var pluginInstance = (BackgroundThreadPlugin)this.Assembly.CreateInstance(this.TypeInfo.FullName); var initMethod = typeof(BackgroundThreadPlugin).GetMethod("Init", BindingFlags.Instance | BindingFlags.NonPublic); // var initMethod = typeof(BackgroundThreadPlugin).GetMethod("Init", BindingFlags.Instance | BindingFlags.NonPublic); if (initMethod != null) { var instanceWrapper = new BackgroundThreadPluginInstance(endpoint, pluginInstance); var logExceptionCallback = new Action <Exception, string>((exception, additionalInfo) => { // TODO: Throttle logging if it happens too frequently. Possibly stop plugin if too many exceptions? ExceptionLogger.LogException(exception, new Controllers.ExecController.ExecOptions() { project = endpoint.Application.Project.Name, application = endpoint.Application.Name, endpoint = endpoint.Name, schema = "BG PLUGIN", routine = this.PluginName, type = Controllers.ExecController.ExecType.BackgroundThread }, additionalInfo, $"BG PLUGIN - {this.PluginName}", endpoint.Pedigree); }); var openSqlConnectionCallback = new Func <SqlConnection>(() => { try { var execConn = endpoint.GetSqlConnection(); if (execConn == null) { throw new Exception($"Execution connection not configured on endpoint {endpoint.Pedigree}"); } var cb = new SqlConnectionStringBuilder(execConn.ConnectionStringDecrypted); cb.ApplicationName = $"{this.PluginName}"; var sqlCon = new SqlConnection(cb.ConnectionString); sqlCon.Open(); return(sqlCon); } catch (Exception ex) { ExceptionLogger.LogExceptionThrottled(ex, $"{this.PluginName}-{endpoint.Pedigree}::OpenSqlConnection", 20); throw; } }); var updateDataCallback = new Func <ExpandoObject, bool>(data => { dynamic eo = data; eo.InstanceId = instanceWrapper.Id; eo.Endpoint = endpoint.Pedigree; hubClients.Group(Hubs.BackgroundPluginHub.ADMIN_GROUP_NAME).SendAsync("updateData", (object)eo); return(true); }); var browserConsoleSendCallback = new Func <string, string, bool>((method, line) => { hubClients.Group(Hubs.BackgroundPluginHub.BROWSER_CONSOLE_GROUP_NAME).SendAsync(method, new { InstanceId = instanceWrapper.Id, Endpoint = endpoint.Pedigree, Line = line }); return(true); }); var addToGroupAsync = new Func <string, string, CancellationToken, Task>((connectionId, groupName, cancellationToken) => { return(hub.Groups.AddToGroupAsync(connectionId, $"{endpoint.Pedigree}.{groupName}", cancellationToken)); }); var sendToGroupsAsync = new Func <string, string, object[], Task>((groupName, methodName, args) => { groupName = $"{endpoint.Pedigree}.{groupName}"; if (args == null || args.Length == 0) { return(hub.Clients.Groups(groupName).SendAsync(methodName)); } else if (args.Length == 1) { return(hub.Clients.Groups(groupName).SendAsync(methodName, args[0])); } else if (args.Length == 2) { return(hub.Clients.Groups(groupName).SendAsync(methodName, args[0], args[1])); } else if (args.Length == 3) { return(hub.Clients.Groups(groupName).SendAsync(methodName, args[0], args[1], args[2])); } else if (args.Length == 4) { return(hub.Clients.Groups(groupName).SendAsync(methodName, args[0], args[1], args[2], args[3])); } else if (args.Length == 5) { return(hub.Clients.Groups(groupName).SendAsync(methodName, args[0], args[1], args[2], args[3], args[4])); } else if (args.Length == 6) { return(hub.Clients.Groups(groupName).SendAsync(methodName, args[0], args[1], args[2], args[3], args[4], args[5])); } else if (args.Length == 7) { return(hub.Clients.Groups(groupName).SendAsync(methodName, args[0], args[1], args[2], args[3], args[4], args[5], args[6])); } else if (args.Length == 8) { return(hub.Clients.Groups(groupName).SendAsync(methodName, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7])); } else if (args.Length == 9) { return(hub.Clients.Groups(groupName).SendAsync(methodName, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8])); } else if (args.Length == 10) { return(hub.Clients.Groups(groupName).SendAsync(methodName, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9])); } return(null); }); var dataCollectorBeginCallback = new Func <string, string, string>((schema, routine) => { string dataCollectorEntryShortId = DataCollectorThread.Enqueue(endpoint, new Controllers.ExecController.ExecOptions() { project = endpoint.Application.Project.Name, application = endpoint.Application.Name, endpoint = endpoint.Name, schema = schema, routine = routine, type = Controllers.ExecController.ExecType.BackgroundThread, inputParameters = new Dictionary <string, string>() // TODO: needs to be an input parameter }); return(dataCollectorEntryShortId); }); initMethod.Invoke(pluginInstance, new object[] { endpoint.Pedigree, logExceptionCallback, openSqlConnectionCallback, updateDataCallback, browserConsoleSendCallback, addToGroupAsync, sendToGroupsAsync, null /*configKeys*/, null /*configSource*/ }); { var setGetServicesFuncMethod = typeof(PluginBase).GetMethod("SetGetServicesFunc", BindingFlags.Instance | BindingFlags.NonPublic); if (setGetServicesFuncMethod != null) { setGetServicesFuncMethod.Invoke(pluginInstance, new object[] { new Func <Type, PluginService>(serviceType => { if (serviceType == typeof(BlobStoreBase)) { return(BlobStore.Instance); } return(null); }) }); } } this.AddEnpointInstance(endpoint, instanceWrapper); SessionLog.Info($"BG plugin '{this.PluginName}' instantiated successfully on endpoint {endpoint.Pedigree}"); } else { throw new Exception("Expected Init method not found"); } } catch (Exception ex) { SessionLog.Error($"Failed to instantiate plugin '{this.PluginName}' ({this.PluginGuid}) from assembly {this.Assembly.FullName} on endpoint {endpoint.Pedigree}. See exception that follows."); SessionLog.Exception(ex); } } }
public static string GetTypescriptTypeFromSql(string sqlType, Dictionary <string, Dictionary <string, RoutineParameterCustomType> > customType, ref ConcurrentDictionary <string, string> customTypeLookupWithTypeScriptDef) { var elems = sqlType.ToLower().Split('.'); // types like geography could come through as sys.CATALOG.geography var dt = elems[elems.Length - 1]; switch (dt) { case Strings.SQL.TABLE_TYPE: return(Strings.TS.OBJECT); case Strings.SQL.TIME: return(Strings.TS.DATE); case Strings.SQL.DATE: return(Strings.TS.DATE); case Strings.SQL.DATETIME: return(Strings.TS.DATE); case Strings.SQL.SMALLDATETIME: return(Strings.TS.DATE); case Strings.SQL.INT: return(Strings.TS.NUMBER); case Strings.SQL.SMALLINT: return(Strings.TS.NUMBER); case Strings.SQL.BIGINT: return(Strings.TS.NUMBER); case Strings.SQL.REAL: return(Strings.TS.NUMBER); case Strings.SQL.BIT: return(Strings.TS.BOOLEAN); case Strings.SQL.NVARCHAR: return(Strings.TS.STRING); case Strings.SQL.VARCHAR: return(Strings.TS.STRING); case Strings.SQL.TEXT: return(Strings.TS.STRING); case Strings.SQL.NTEXT: return(Strings.TS.STRING); case Strings.SQL.VARBINARY: return(Strings.TS.BLOB); // TODO: Not sure about this one...worst case, make it a string case Strings.SQL.DECIMAL: return(Strings.TS.NUMBER); case Strings.SQL.UNIQUEIDENTIFIER: return(Strings.TS.STRING); case Strings.SQL.MONEY: return(Strings.TS.NUMBER); case Strings.SQL.CHAR: return(Strings.TS.STRING); case Strings.SQL.NCHAR: return(Strings.TS.STRING); case Strings.SQL.XML: return(Strings.TS.STRING); case Strings.SQL.FLOAT: return(Strings.TS.NUMBER); case Strings.SQL.IMAGE: return(Strings.TS.BLOB); // TODO: Not sure about this one...worst case, make it a string case Strings.SQL.TINYINT: return(Strings.TS.NUMBER); case Strings.SQL.GEOGRAPHY: return(Strings.TS.jsDAL_LatLng); case Strings.SQL.SQL_VARIANT: return(Strings.TS.STRING); case Strings.SQL.TIMESTAMP: return(Strings.TS.STRING); case Strings.SQL.BINARY: return(Strings.TS.BLOB); // TODO: Not sure about this one...worst case, make it a string case Strings.SQL.NUMERIC: return(Strings.TS.NUMBER); case Strings.SQL.SYSNAME: return(Strings.TS.ANY); default: { if (customType != null && customType.Keys.Count > 0) { //? lock (customTypeLookupWithTypeScriptDef) { var customTypeName = customType.Keys.First(); var typeName = $"$CustomType_{customTypeName}"; if (customTypeLookupWithTypeScriptDef.ContainsKey(typeName)) { return(typeName); } var properties = new Dictionary <string, string>(); foreach (var kv in customType[customTypeName]) { var fieldName = kv.Key; var dataType = kv.Value.DataType; var tsTypeDef = GetTypescriptTypeFromSql(kv.Value.DataType, null, ref customTypeLookupWithTypeScriptDef); properties.Add(fieldName, tsTypeDef); } var customTSD = string.Join(", ", from kv in properties select $"{kv.Key}: {kv.Value}"); //TODO: Custom types are not necessarily arrays? if (!customTypeLookupWithTypeScriptDef.TryAdd(typeName, $"{{{ customTSD }}}[]")) { SessionLog.Error($"Failed to add custom type {typeName} to dictionary"); } return(typeName); } } return("any"); } } }