# Appservice

Interfaces to handle app services and app instances.
Basically each App has one class which is derived from the base class AppService. This base class establishes a unix domain socket connection to the manager app, which controlls the creation, starting and stopping of instances.
Each instance itself is derived from AppInstance and gets its own AppInstanceArgs.

## File information

File | common/lib/appservice.h
Classes | AppService AppInstance AppServiceApp AppInstancePlugin AppServiceSocket UAppServiceSocket
Data types | ServiceAlarmSeverity ServiceAlarmType AppServiceArgs AppInstanceArgs
Examples | Example

### Logging

To enable logging for apps, the flag LOG_APP must be set in the managers diagnostic settings.

# Classes

## AppService

The service class of the App must be derived from the class AppService and implement the neccessary virtual functions.

    class AppService : public UAppServiceSocket, public IInstanceLog {
    public:
        AppService(class IIoMux * const iomux, class ISocketProvider * const localSocketProvider, AppServiceArgs * serviceArgs);

        virtual class AppInstance * CreateInstance(AppInstanceArgs * args) = 0;
        virtual void AppServiceApps(istd::list * appList) = 0;
        virtual void AppInstancePlugins(istd::list * pluginList) {};

        void AppStart(AppInstanceArgs * args) override;
        void AppStopped(class AppInstance * instance);
        const char * GetAppServiceId() const;
        const char * GetAppPlatformDNSName() const;
        const char * GetAppPlatformTimeZoneString() const;
        const char * GetAppPlatformTimeZone() const;
        ISocketContext::tls_profile_t GetTlsProfile();
        word GetWebserverPortHttp();
        word GetWebserverPortHttps();
        void SetAllInstancesLogFlags(ulong64 logFlags);
    };

### Public functions

AppService

  Constructor

  #### Parameters

  class IIoMux * const iomux | An IIoMux pointer to the IIoMux class.
  ISocketProvider * const localSocketProvider | An ISocketProvider pointer to a local socket provider.
  AppServiceArgs * serviceArgs | An AppServiceArgs pointer to the service arguments struct.

CreateInstance

  You must override this function inside your class which implements the AppService class.
  This function creates an object of the instance class of the App which must be derived from the class AppInstance.
  If this object is stopped and has finished stopping, it must call AppStopped, see below.

  #### Parameters

  AppInstanceArgs * args | An AppInstanceArgs pointer to the instance arguments.

  #### Return value

  The created AppInstance object.

AppServiceApps

  You must override this function inside your class which implements the AppService class.
  Push your provided apps to the appList. Each app has to be an instance of class AppServiceApp. An app of an AppService might be configured inside the PBX App object.

  #### Parameters

  istd::list<AppServiceApp> * appList | A list to add all AppServiceApps.

AppInstancePlugins

  You can override this function inside your class which implements the AppService class if your app provides app instance plugins (PBX manager plugins).
  Push your provided plugins to the pluginList. Each app has to be an instance of class AppInstancePlugin.
  See publish manager plugins for further reference.

  #### Parameters

  istd::list<AppInstancePlugin> * pluginList | A list to add all AppInstancePlugins.

AppStart

  You can start an own app instance, e.g. inside your app-main.cpp, if you want to start an instance outside of the manager control.

  #### Parameters

  AppInstanceArgs * args | An AppInstanceArgs pointer to the instance arguments.

AppStopped

  Call this function when your app stopped.

  #### Parameters

  AppInstance * instance | An AppInstance pointer to the instance object.

GetAppServiceId

  #### Return value

  The service id of the app service.

GetAppPlatformDNSName

  #### Return value

  The app platform DNS name which can be configured inside the manager settings.

GetAppPlatformTimeZoneString

  #### Return value

  The app platform POSIX timezone string which can be configured inside the manager settings.

GetAppPlatformTimeZone

  #### Return value

  The app platform IANA timezone string which can be configured inside the manager settings.

GetTlsProfile

  #### Return value

  The current ISocketContext::tls_profile_t TLS profile.

GetWebserverPortHttp

  #### Return value

  A word which is the local webserver http port.

GetWebserverPortHttps

  #### Return value

  A word which is the local webserver https port.

SetAllInstancesLogFlags

  Call this function if you want to set the logFlags of all instances to a certain value.

  #### Parameters

  ulong64 logFlags | The logFlags to set.

## AppInstance

The instance class of an App must be derived from AppInstance and implement the neccessary virtual functions.

    class AppInstance : public IInstanceLog {
    public:
        AppInstance(class AppService * appService, AppInstanceArgs * args, bool autoStart = true)
        void Started();
        const char * GetAppServiceId() const;
        const char * GetAppName() const;
        const char * GetAppDomain() const;
        const char * GetKey() const;
        void SetLogFlags(ulong64 logFlags);
        static char * GenerateKey(const char * appName, const char * appDomain);
        void LogV(const char * format, va_list ap);
        void Log(const char * format, ...);
        void HexDump(const void * buffer, size_t size);
        void SetAlarm(word code, ServiceAlarmSeverity severity, char * text, char * details);
        void ClearAlarm(word code, ServiceAlarmSeverity severity, char * text, char * details);
        void SendEvent(word code, ServiceAlarmSeverity severity, char * text, char * details);
        virtual void Stop() = 0;
        virtual void ServerCertificateUpdate(const byte * cert, size_t certLen) {};
        virtual void AppPlatformTimeZoneUpdate(const char * timeZone) {};
        virtual void SetAppDomain(const char * domain, const char * pwd) {};
        virtual void TlsProfileUpdate(ISocketContext::tls_profile_t tlsProfile) {};
    };

### Public functions

AppInstance

  Constructor

  #### Parameters

  AppService * service | An AppService pointer to the app service class.
  AppInstanceArgs * instanceArgs | An AppInstanceArgs pointer to the instance arguments struct.
  bool autoStart | Default true. If false is handed, you must yourself call AppInstance::Started() when your instance is ready. There shouldn't be a need for your App to set autoStart to false.

Started

  Just use, if you set autoStart false in the constructer. Call this function if your instance is ready so that the App Platform Manager knows it.

GetAppServiceId

  #### Return value

  The app service id.

GetAppName

  #### Return value

  The app name.

GetAppDomain

  #### Return value

  The app domain.

GetKey

  #### Return value

  The unique key string which identifies the app instance: "appname@appdomain".

SetLogFlags

  Call this function to set the logFlags of the instance.

  #### Parameters

  ulong64 logFlags | The logFlags to set.

GenerateKey (static function)

  Generates the unique string which identifies an intance.

  #### Parameters

  const char * appName | The app name.
  const char * appDomain | The app domain.

  #### Return value

  The unique key string which identifies the app instance: "appname@appdomain". Must be freed by the caller!

LogV

  Writes the log string to the debug output (e.g. file or debugging output).

  #### Parameters

  const char * format | The format string.
  va_list ap | A variable argument list with all arguments which are used inside the format string.

Log

  Writes the log string to the debug output (e.g. file or debugging output).

  #### Parameters

  const char * format | The format string.
  ... | Further arguments used inside format string.

HexDump

  Writes a hexdump of the buffer to the debug output (e.g. file or debugging output).

  #### Parameters

  const void * buffer | The buffer.
  size_t size | The size to dump.

SetAlarm

  Sets an alarm, which is sent to the manager (which again sends it to an alarm and events server). An alarm is active until it is cleared.

  #### Parameters

  word code | A code to identify an alarm.
  ServiceAlarmSeverity severity | The severity.
  char * text | The text which identifies the alarm.
  char * details | Further details for the alarm.

ClearAlarm

  Clears an alarm.

  #### Parameters

  See SetAlarm for parameter reference.

SendEvent

  Sends an event.

  #### Parameters

  See SetAlarm for parameter reference.

Stop

  You must override this function. It is called if the instance or service is stopped by the manager.
  You must call AppService::AppStopped asynchronously if everything has been stopped.

ServerCertificateUpdate

  You can override this function if you need to be notified about the webserver certificate. You can then pass the certificate to an ISocketContext.

  #### Parameters

  const byte * cert | The certificate byte buffer.
  size_t certLen | The length of the byte buffer.

AppPlatformTimeZoneUpdate

  You can override this function if you need to be notified about a change of the IANA timezone configuration value.

  #### Parameters

  const char * timeZone | The IANA time zone name.

SetAppDomain

  Shouldn't be used inside app code.

TlsProfileUpdate

  You can override this function if you need to be notified about a change of the TLS profile.

  #### Parameters

  ISocketContext::tls_profile_t tlsProfile | The new TLS profile setting.

## AppServiceApp

The class AppServiceApp is used to describe an app which is provided by an AppService. Each app has a (for the service) unique name, which will be later used inside the URL which points to the app of the AppService.

    class AppServiceApp {
    public:
        AppServiceApp(const char * name, bool websocketOnly = false);
        const char * GetName();
        bool IsWebsocketOnly();
    };

### Public functions

AppServiceApp

  Constructor

  #### Parameters

  const char * name | The name describes the last URL part of the app.
  bool websocketOnly | An app which can be just used with a websocket connection.

GetName

  #### Return value

  The name.

IsWebsocketOnly

  #### Return value

  The websocketOnly value.

## AppInstancePlugin

The class AppInstancePlugin is used to describe an app instance plugin.

    class AppInstancePlugin {
    public:
        AppInstancePlugin(const char * plugin, const char * icon, const char * langFile, bool wildcard = false, const char * api = NULL);

        bool wildcard;

        const char * GetIcon();
        const char * GetApi();
        const char * GetPlugin();
        const char * GetLangFile();
    };

### Public functions

See publish manager plugins for further reference.

## AppServiceSocket

This class is just used internally inside the manager and webserver.

## UAppServiceSocket

This class is just used internally inside the manager and webserver.

# Data types

## ServiceAlarmSeverity

    typedef enum {
        ALARM_SEVERITY_INDETERMINATE,
        ALARM_SEVERITY_MAJOR,
        ALARM_SEVERITY_CRITICAL
    } ServiceAlarmSeverity;

### Overview

The `enum ServiceAlarmSeverity` is used to determine the severity of an alarm.

## ServiceAlarmType

    typedef enum {
        ALARM_TYPE_SET,
        ALARM_TYPE_CLEAR,
        ALARM_TYPE_ERROR
    } ServiceAlarmType;

### Overview

The `enum ServiceAlarmType` is used to determine the alarm type.

## AppServiceArgs

    struct AppServiceArgs {
        void Parse(int argc, char ** argv, bool keepDefaults = true);
        const char * serviceID;
        const char * manager;
        const char * appPlatformDNSName;
        ulong64 logFlags;
        bool segfaulted;
        bool disableHexdumps;
        off_t logFileSize;
    };

### Overview

The `struct AppServiceArgs` holds the relevant app service arguments. App service arguments are defined inside the manager.
The AppService class gets them through command line arguments which are usually parsed inside the app-main.cpp.

### Parameters

const char * serviceID |
const char * manager | The unix domain socket file of the manager.
const char * appPlatformDNSName |
ulong64 logFlags |
bool segfaulted | Indicates if the service previously segfaulted.
bool disableHexdumps | This is set to true if hexdumps are disabled.
off_t logFileSize | The maximum log file size.

## AppInstanceArgs

    struct AppInstanceArgs {
        AppInstanceArgs();
        void Parse(int argc, char ** argv, bool keepDefaults = true);
        const char * appName;
        const char * appDomain;
        const char * appPassword;
        const char * webserver;
        const char * webserverPath;
        const char * dbHost;
        const char * dbName;
        const char * dbUser;
        const char * dbPassword;
        const char * workingPath;
        ulong64 logFlags;
    };

### Overview

The `struct AppInstanceArgs` holds the relevant app instance arguments. App instance arguments are defined inside the manager.
The AppService class gets them through the socket connection and uses them to create a new AppInstance class.

### Parameters

const char * appName |
const char * appDomain |
const char * appPassword |
const char * webserver | The unix domain socket file which is used to connect to the webserver.
const char * webserverPath | The relative path which is used to access the application via HTTP.
const char * dbHost | Usually an empty string, as the connection is done with unix domain sockets to the local database server.
const char * dbName |
const char * dbUser |
const char * dbPassword |
const char * workingPath |
ulong64 logFlags |

# Code Example

    class TestInstance : public AppInstance {
        ISocketContext * socketContext;
        ISocket * socket;
        void Stop() override;
        void ServerCertificateUpdate(const byte * cert, size_t certLen)  override;
        void TryStop();
    public:
        TestInstance(class IIoMux * const iomux, class TestService * testService, class ISocketProvider * localSocketProvider, class IDatabaseProvider * databaseProvider, class IWebserverPluginProvider * webserverPluginProvider, AppInstanceArgs * instanceArgs);
        ~TestInstance();
    };

    class TestService : public AppService {
        class IIoMux * const iomux;
        class ISocketProvider * localSocketProvider;
        class ISocketProvider * tlsSocketProvider;
        class IDatabaseProvider * databaseProvider;
        class IWebserverPluginProvider * webserverPluginProvider;
    public:
        TestService(class IIoMux * const iomux, class ISocketProvider * localSocketProvider, class ISocketProvider * tlsSocketProvider, class IDatabaseProvider * databaseProvider, class IWebserverPluginProvider * webserverPluginProvider, AppServiceArgs * serviceArgs);
        ~TestService();
        class AppInstance * CreateInstance(AppInstanceArgs * instanceArgs) override;
        void AppServiceApps(class json_io & json, word base) override;
    };

    TestService::TestService(class IIoMux * const iomux, class ISocketProvider * localSocketProvider, class ISocketProvider * tlsSocketProvider, class IDatabaseProvider * databaseProvider, class IWebserverPluginProvider * webserverPluginProvider,  AppServiceArgs * serviceArgs)
        : AppService(iomux, localSocketProvider, serviceArgs),
        iomux(iomux)
    {
        this->databaseProvider = databaseProvider;
        this->localSocketProvider = localSocketProvider;
        this->tlsSocketProvider = tlsSocketProvider;
        this->webserverPluginProvider = webserverPluginProvider;
    }

    TestService::~TestService()
    {
    }

    class AppInstance * TestService::CreateInstance(AppInstanceArgs * instanceArgs)
    {
        return new class TestInstance(iomux, this, localSocketProvider, tlsSocketProvider, databaseProvider, webserverPluginProvider, instanceArgs);
    }

    void TestService::AppServiceApps(istd::list<AppServiceApp> * appList)
    {
        appList->push_back(new AppServiceApp("devices"));
        appList->push_back(new AppServiceApp("sysclients", true));
    }

    TestInstance::TestInstance(class IIoMux * const iomux, class TestService * testService, class ISocketProvider * localSocketProvider, class ISocketProvider * tlsSocketProvider, class IDatabaseProvider * databaseProvider, class IWebserverPluginProvider * webserverPluginProvider, AppInstanceArgs * instanceArgs) :
    AppInstance(testService, instanceArgs)
    {
        this->iomux = iomux;
        this->databaseProvider = databaseProvider;
        this->webserverPlugin = webserverPluginProvider->CreateWebserverPlugin(iomux, localSocketProvider, this);
        this->socketContext = tlsSocketProvider->CreateSocketContext(this);
        this->socket = tlsSocketProvider->CreateSocket(iomux, NULL, this, false, socketContext);
        webserverPlugin->RegisterForPath(instanceArgs->webserver, instanceArgs->webserverPath);
        this->Log("TestInstance created");
    }
    TestInstance::~TestInstance()
    {
        this->Log("TestInstance deleted");
    }
    void TestInstance::ServerCertificateUpdate(const byte * cert, size_t certLen)
    {
        this->socketContext->SetServerCertificate(cert, certLen, NULL);
    }
    void TestInstance::Stop()
    {
        TryStop();
    }
    void TestInstance::TryStop()
    {
        // if everything has been closed, call AppStopped
        appService->AppStopped(this);
    }