'Keiki Usage Meter' Logo

Plugin Development

Keiki Usage Meter plugins are implemented as .NET class libraries. The UsageContract library (UsageContract.dll) contains definitions for the IUsageRetriever interface and UsageData structure, shown below. Plugins need to implement the former interface, which involves writing a method that returns the latter structure. Create a class library and add a reference to this DLL in order to create a plugin.

Localisation

The sample usage retriever below contains English and Japanese translations. Each metadata field should be an array of strings (all of the same length). The first item in any of these arrays must not be null; other items will use the value from the first item if they are set to null.

Plugin Image

You may include an image with the plugin. This should be a 128x128 pixel TIFF file named Image.tif, included in the project as a resource. Ideally, the image should be a multi-frame TIFF, rendered at 128x128 pixels for 96 DPI, 160x160 pixels for 120 DPI, 192x192 pixels for 144 DPI and 256x256 pixels for 192 DPI. Use my PNG to Multi-DPI TIFF program to generate these images.

IUsageRetriever Interface

    /// <summary>
    /// The UsageRetriever interface.
    /// </summary>
    public interface IUsageRetriever
    {
        /// <summary>
        /// Retrieves usage.
        /// </summary>
        /// <param name="username">
        /// The username.
        /// </param>
        /// <param name="password">
        /// The password.
        /// </param>
        /// <param name="cancellationToken">
        /// Cancellation token.
        /// </param>
        /// <param name="debugMode">
        /// Indicates whether errors should be logged.
        /// </param>
        /// <returns>
        /// Set of usage values in <see cref="UsageData"/> structure.
        /// </returns>
        UsageData RetrieveUsage(string username, string password, CancellationTokenSource cancellationToken, bool debugMode);
    }

UsageData Structure

    /// <summary>
    /// Usage data structure.
    /// </summary>
    public struct UsageData
    {
        /// <summary>
        /// Indicates whether the usage retrieval operation was cancelled or not.
        /// </summary>
        public bool Cancelled;

        /// <summary>
        /// Holds exception data from the update process.
        /// </summary>
        public Exception UpdateException;

        /// <summary>
        /// Represents the plan name, or "?" if this is unknown.
        /// </summary>
        public string PlanName;

        /// <summary>
        /// Date of update.
        /// </summary>
        public DateTime CurrentDate;

        /// <summary>
        /// Period start date.
        /// </summary>
        public DateTime PeriodStartDate ;

        /// <summary>
        /// Period end date.
        /// </summary>
        public DateTime PeriodEndDate;

        /// <summary>
        /// Time zone used.
        /// </summary>
        public TimeZoneInfo TimeZone;

        /// <summary>
        /// Peak usage value.
        /// </summary>
        public double PeakData;

        /// <summary>
        /// Peak download usage value.
        /// </summary>
        public double PeakDownload;

        /// <summary>
        /// Peak upload usage value.
        /// </summary>
        public double PeakUpload;

        /// <summary>
        /// Peak total value.
        /// </summary>
        public double PeakDataTotal;

        /// <summary>
        /// Off peak usage value.
        /// </summary>
        public double OffPeakData;

        /// <summary>
        /// Off peak download usage value.
        /// </summary>
        public double OffPeakDownload;

        /// <summary>
        /// Off peak upload usage value.
        /// </summary>
        public double OffPeakUpload;

        /// <summary>
        /// Off peak total value.
        /// </summary>
        public double OffPeakDataTotal;
    }

Sample Usage Retriever

Download SampleUsageRetriever.7z
namespace SampleUsageRetriever
{
    using System;
    using System.ComponentModel.Composition;
    using System.Threading;

    using UsageContract;

    public class Usage
    {
        /// <summary>
        /// Retrieves usage from Optus (legacy plans).
        /// </summary>
        [Export(typeof(IUsageRetriever))]
        [ExportMetadata("Name", new[] { "Sample Usage Retriever", "サンプルプラグイン" })]
        [ExportMetadata("Description", new[] { "Test usage retriever for debugging.", "デバッグ用のプラグイン。" })]
        [ExportMetadata("Author", new[] { "David Warner", null })]
        [ExportMetadata("AuthorURL", new[] { "https://www.quppa.net", null })]
        [ExportMetadata("Languages", new[] { "en-AU", "ja-JP" })]
        public class DebugUpdater : IUsageRetriever
        {
            /// <summary>
            /// Retrieves usage.
            /// </summary>
            /// <param name="cancellationToken">
            /// Cancellation token.
            /// </param>
            /// <returns>
            /// Set of usage values in <see cref="UsageData"/> structure.
            /// </returns>
            public UsageData RetrieveUsage(string username, string password, CancellationTokenSource cancellationToken, bool debugMode)
            {
                UsageData result = new UsageData { Cancelled = false };

                try
                {
                    // sleep here to simulate network activity
                    Thread.Sleep(5000);

                    cancellationToken.Token.ThrowIfCancellationRequested();

                    result.PlanName = "Test Plan Name";

                    TimeZoneInfo timezone = TimeZoneInfo.Utc;

                    result.TimeZone = timezone;
                    result.PeriodStartDate = DateTime.SpecifyKind(new DateTime(DateTime.UtcNow.Year, DateTime.UtcNow.Month, 1), DateTimeKind.Utc);
                    result.PeriodEndDate = DateTime.SpecifyKind(result.PeriodStartDate.AddMonths(1).AddDays(-1), DateTimeKind.Utc);
                    result.CurrentDate = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc);

                    result.PeakDataTotal = 250000;
                    result.OffPeakDataTotal = 250000;
                    result.PeakData = 225000;
                    result.OffPeakData = 100000;
                    result.PeakUpload = 75000;
                    result.PeakDownload = 150000;
                    result.OffPeakUpload = 25000;
                    result.OffPeakDownload = 75000;
                }
                catch (Exception ex)
                {
                    result.UpdateException = ex;
                }

                result.Cancelled = cancellationToken.Token.IsCancellationRequested;

                return result;
            }
        }
    }
}