Esempio n. 1
0
 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));
        }
Esempio n. 3
0
        //--- 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);
            }
        }
Esempio n. 4
0
        //--- 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();
        }