public void DeregisterService(uint serviceId) { lock (_serviceExpirations) { TaskTimer timer; if (_serviceExpirations.TryGetValue(serviceId, out timer)) { timer.Cancel(); _serviceExpirations.Remove(serviceId); } } ServiceRepository.IServiceInfo serviceInfo = RunningServices[serviceId]; if (serviceInfo == null) { _log.DebugFormat("cannot destroy service {0}, already destroyed", serviceId); return; } if (serviceInfo.IsLocal) { Plug location = Plug.New(serviceInfo.ServiceUri); if (location != null) { location.DeleteAsync().Wait(); } } RunningServices.DeregisterService(serviceInfo); }
public Yield ProxyToService(DreamContext context, DreamMessage request, Result <DreamMessage> response) { PermissionsBL.IsUserAllowed(DekiContext.Current.User, Permissions.ADMIN); //Private feature requires api-key var identifier = context.GetParam("id"); ServiceRepository.IServiceInfo serviceInfo = null; if (identifier.StartsWith("=")) { serviceInfo = DekiContext.Current.Instance.RunningServices[XUri.Decode(identifier.Substring(1))]; } else { uint serviceId; if (uint.TryParse(identifier, out serviceId)) { serviceInfo = DekiContext.Current.Instance.RunningServices[serviceId]; } else { throw new DreamBadRequestException(string.Format("Invalid id '{0}'", identifier)); } } if (serviceInfo == null) { throw new ServiceNotFoundException(identifier); } var proxyUri = serviceInfo.ServiceUri.At(context.GetSuffixes(UriPathFormat.Original).Skip(1).ToArray()); yield return(context.Relay(Plug.New(proxyUri), request, response)); }
//--- Class Methods --- public static ServiceBE StartService(ServiceBE service, bool forceRefresh, bool disableOnFailure) { // create subordinate request id for service start var dreamContext = DreamContext.Current; var requestId = dreamContext.GetState <string>(DreamHeaders.DREAM_REQUEST_ID); dreamContext.SetState(DreamHeaders.DREAM_REQUEST_ID, requestId + "-service_" + service.Id); try { var stopwatch = Stopwatch.StartNew(); service.ServiceLastStatus = string.Empty; StopService(service.Id, service, ServiceStopType.Restart); DekiContext context = DekiContext.Current; bool dirtyServiceEntity = false; XUri location; ServiceRepository.IServiceInfo serviceInfo = null; try { // check if service is local if (service.ServiceLocal) { if (string.IsNullOrEmpty(service.SID)) { throw new Exception("missing SID"); } // start service if (IsLocalAuthService(service)) { // this service is the built-in authentication provider; no need to start it location = context.Deki.Self; } else { // convert local service configuration into an xdoc XDoc config = new XDoc("config"); foreach (KeyValuePair <string, string> configEntry in ArrayUtil.AllKeyValues(service.Config)) { config.InsertValueAt(configEntry.Key, configEntry.Value); } // if no apikey was provided, create a random one so that CreateService doesn't inject the parent one if (config["apikey"].IsEmpty) { config.Elem("apikey", StringUtil.CreateAlphaNumericKey(16)); } // add information for service to callback into deki if (config["uri.deki"].IsEmpty) { config.Elem("uri.deki", context.Deki.Self); config.Elem("wikiid.deki", context.Instance.Id); // Providing master apikey to service for setups that don't use per instance keys config.Elem("apikey.deki", context.Instance.ApiKey.IfNullOrEmpty(context.Deki.MasterApiKey)); } // the service location must use the service ID and the instance ID string servicePath = string.Format("services/{0}/{1}", context.Instance.Id, service.Id); _log.DebugFormat("starting service '{0}' at path {1} w/ namespace {2}", service.SID, servicePath, service.Preferences["namespace"]); serviceInfo = context.Instance.CreateLocalService(service, servicePath, config); location = serviceInfo.ServiceUri; } // check if the service uri has changed since last invocation (happens when service is started for the first time or server GUID has changed) if (!service.Uri.EqualsInvariantIgnoreCase(location.ToString())) { dirtyServiceEntity = true; service.Uri = location.ToString(); } } else { _log.DebugFormat("registering remote service '{0}'", service.SID); if (string.IsNullOrEmpty(service.Uri)) { throw new Exception("missing URI"); } location = new XUri(service.Uri); serviceInfo = context.Instance.RegisterRemoteService(service, location); } // check if service is an Extension service if (service.Type == ServiceType.EXT) { if (service.ServiceLocal) { _log.DebugFormat("registering service '{0}' as extension", service.SID); } ExtensionBL.StartExtensionService(context, service, serviceInfo, forceRefresh); } //Successfully starting a service enables it. if (!service.ServiceEnabled) { dirtyServiceEntity = true; service.ServiceEnabled = true; } } catch (Exception e) { dirtyServiceEntity = true; DreamMessage dm = null; if (e is DreamResponseException) { dm = ((DreamResponseException)e).Response; string message = dm.HasDocument ? dm.ToDocument()[".//message"].AsText.IfNullOrEmpty(e.Message) : dm.ToText(); service.ServiceLastStatus = string.Format("unable to initialize service ({0})", message); } else { service.ServiceLastStatus = e.GetCoroutineStackTrace(); } if (serviceInfo != null) { try { context.Instance.DeregisterService(service.Id); } catch { } } // A service that fails to start becomes disabled if it's started explicitly (not during deki startup) if (disableOnFailure) { service.ServiceEnabled = false; } _log.ErrorExceptionMethodCall(e, "StartService", string.Format("Unable to start local service id '{0}' with SID '{1}' Error: '{2}'", service.Id, service.SID, service.ServiceLastStatus)); if (dm != null) { throw new ExternalServiceResponseException(dm); } else { throw; } } finally { // don't update remote services that haven't changed if (dirtyServiceEntity) { service = UpdateService(service); } } stopwatch.Stop(); _log.InfoFormat("Service '{0}' ({1}) started in {2}ms", service.Description, service.SID, stopwatch.ElapsedMilliseconds); return(service); } finally { // restore the request id dreamContext.SetState(DreamHeaders.DREAM_REQUEST_ID, requestId); } }
//--- Class Methods --- public static void StartExtensionService(DekiContext context, ServiceBE service, ServiceRepository.IServiceInfo serviceInfo, bool forceRefresh) { // retrieve document describing the extension functions XUri uri = new XUri(service.Uri); XDoc manifest = null; DekiWikiService deki = context.Deki; var extension = serviceInfo.Extension; if (!service.ServiceLocal) { lock (deki.RemoteExtensionLibraries) { deki.RemoteExtensionLibraries.TryGetValue(uri, out manifest); } } if (manifest == null || forceRefresh) { manifest = Plug.New(uri).Get().ToDocument(); // normalize the extension XML manifest = manifest.TransformAsXml(_extensionConverterXslt); // check if document describes a valid extension: either the extension has no functions, or the functions have end-points if (manifest.HasName("extension") && ((manifest["function"].ListLength == 0) || (manifest["function/uri"].ListLength > 0))) { // add source uri for service manifest.Attr("uri", uri); // register service in extension list lock (deki.RemoteExtensionLibraries) { deki.RemoteExtensionLibraries[uri] = manifest; } } else { throw new ExtensionRemoveServiceInvalidOperationException(uri); } } extension.Manifest = manifest; // add function prefix if one is defined serviceInfo.Extension.SetPreference("namespace.custom", service.Preferences["namespace"]); string serviceNamespace = service.Preferences["namespace"] ?? manifest["namespace"].AsText; if (serviceNamespace != null) { serviceNamespace = serviceNamespace.Trim(); if (string.IsNullOrEmpty(serviceInfo.Namespace)) { // Note (arnec): Namespace from preferences is assigned at service creation. If we do not have one at this // point, it came from the extension manifest and needs to be registered as our default. Otherwise the // preference override persists as the namespace. context.Instance.RunningServices.RegisterNamespace(serviceInfo, serviceNamespace); } if (serviceNamespace.Length != 0) { if (!DekiScriptParser.IsIdentifier(serviceNamespace)) { throw new ExtensionNamespaceInvalidArgumentException(service.Preferences["namespace"] ?? manifest["namespace"].AsText); } } else { serviceNamespace = null; } } serviceNamespace = (serviceNamespace == null) ? string.Empty : (serviceNamespace + "."); // add custom library title extension.SetPreference("title.custom", service.Preferences["title"]); extension.SetPreference("label.custom", service.Preferences["label"]); extension.SetPreference("description.custom", service.Preferences["description"]); extension.SetPreference("uri.logo.custom", service.Preferences["uri.logo"]); extension.SetPreference("functions", service.Preferences["functions"]); extension.SetPreference("protected", service.Preferences["protected"]); // add each extension function bool.TryParse(service.Preferences["protected"], out extension.IsProtected); var functions = new List <ServiceRepository.ExtensionFunctionInfo>(); foreach (XDoc function in manifest["function"]) { XUri functionUri = function["uri"].AsUri; if (functionUri != null) { functions.Add(new ServiceRepository.ExtensionFunctionInfo(serviceNamespace + function["name"].Contents, functionUri)); } } extension.Functions = functions.ToArray(); }