public WebService(int port, ICredentialValidator credentialsValidator, RestApiConfiguration restApiConfig)
 {
   _port = port;
   _credentialsValidator = credentialsValidator;
   _restApi = new RestApi(restApiConfig);
   Logging = Logger.Instance as ILogging;
 }
    public void Start(Power firmware)
    {
      var config = new RestApiConfiguration();

      config.AddHandler("GET", "/boot/ping", "is server alive")
        .ReturnNothing()
        .HandledBy(() => {});

      config.AddHandler("GET", "/boot/firmware", "get firmware info")
        .ReturnJson()
        .HandledBy(() => firmware.GetFirmwareInfoAsJson());

      config.AddHandler("PUT", "/boot/firmware", "update firmware")
        .ReturnJson()
        .HandledWithStreamBy((s) => firmware.UpdateFirmware(s));

      config.AddHandler("POST", "/boot/sysinfo", "get system state")
        .ReturnJson()
        .HandledBy(() => HardwareInfo.Instance.GetSystemInfo());

      config.AddHandler("POST", "/boot/diskinfo", "list content of filesystem")
        .ReturnJson()
        .HandledBy(() => HardwareInfo.Instance.GetDiskInfo());

      config.AddHandler("GET", "/boot/networks", "list network information")
        .ReturnJson()
        .HandledBy(() => HardwareInfo.Instance.GetNetworkInterfaceInfo());

      config.AddHandler("GET", "/boot/log/full", "get full log")
        .ReturnJson()
        .HandledBy(() => Logger.Instance.Full.GetLinesAsJson());

      config.AddHandler("GET", "/boot/log/errors", "get error log")
        .ReturnJson()
        .HandledBy(() => Logger.Instance.Errors.GetLinesAsJson());

      config.AddHandler("POST", "/boot/ntp/sync", "sync time with NTP")
        .ReturnJson()
        .HandledBy(() =>
        {
          RealTimeClock.Instance.UpdateFromNTP();
          var status = new JsonObject();
          status.Add("time", DateTime.Now);
          return status;
        });

      config.AddHandler("POST", "/boot/reboot", "reboot the device")
        .SetNotes("This will reboot the device and not return")
        .ReturnNothing()
        .HandledBy(() => firmware.Reboot());

      var credentials = CredentialValidatorFactory.CreateSimpleValidator("ChickenHouse", "admin", "hnsefyk");
      var webService = new WebService(c_servicePort, credentials, config);

      string prefix = Name + ": ";
      webService.Logging.OnLogInfo += message => Logger.Instance.LogInfo(prefix + message);
      webService.Logging.OnLogError += message => Logger.Instance.LogError(prefix + message);
      webService.Logging.OnLogException += (message, ex) => Logger.Instance.LogException(prefix + message, ex);
      webService.Start();
    }
    internal RestApi(RestApiConfiguration config)
    {
      ////// Sanity-check all rest handlers. They must have been given a handler.
      ////foreach (RestHandler handler in config.Handlers)
      ////{
      ////  if (handler.Handler == null)
      ////    throw new InvalidOperationException("Missing handler for " + handler.DisplayName);
      ////}
      // todo: warn about missing api descriptions

      // Get builder's info
      _apiBasePath = config.ApiBasePath;

      // Prepare private handlers for swagger-documentation
      var priv = new RestApiConfiguration { ApiBasePath = _apiBasePath };
      priv.AddHandler("GET", "", "Swagger UI")
        .ReturnsString("text/html")
        .HandledBy(GetApiIndex);
      priv.AddHandler("GET", "/api-docs", "API list")
        .ReturnsJson()
        .HandledBy(GetApiResourceListing);
      priv.AddHandler("GET", "/api-docs/{apiname}", "API description")
        .ReturnsJson()
        .HandledBy(GetApiDocs);

      // todo:
      // handle /images/throbber.gif
      // handle /favicon.ico

      foreach (RestHandler handler in config.Handlers)
      {
        var apiname = (config.FlattenApis ? "/all" : handler.ApiName);
        if (!_apis.Contains(apiname))
          _apis[apiname] = new ArrayList();
        (_apis[apiname] as ArrayList).Add(handler);
      }

      // Get the combined handlers
      _handlers = new RestHandler[config.Handlers.Count + priv.Handlers.Count];
      priv.Handlers.CopyTo(_handlers, 0);
      config.Handlers.CopyTo(_handlers, priv.Handlers.Count);
    }
    public void Start(Machinery machinery, DoorScheduler doorScheduler)
    {
      var config = new RestApiConfiguration();

      config.AddHandler("GET", "/sys/ping", "is server alive")
        .ReturnsNothing()
        .HandledBy(() => { });

      config.AddHandler("POST", "/sys/info", "get system state")
        .ReturnsJson()
        .HandledBy(() => HardwareInfo.Instance.GetSystemInfo());

      config.AddHandler("POST", "/sys/disk", "list content of filesystem")
        .ReturnsJson()
        .HandledBy(() => HardwareInfo.Instance.GetDiskInfo());

      config.AddHandler("GET", "/sys/network", "list network information")
        .ReturnsJson()
        .HandledBy(() => HardwareInfo.Instance.GetNetworkInterfaceInfo());

      config.AddHandler("GET", "/sys/time", "get current local time")
        .ReturnsJson()
        .HandledBy(() =>
        {
          var status = new JsonObject();
          status.Add("time", DateTime.Now);
          return status;
        });

      config.AddHandler("PUT", "/sys/time/{time}", "set current local time")
        .ReturnsNothing()
        .HandledBy((time) =>
        {
          // todo
          //Goke.ChickenHouse.HAL.Hardware.Instance.Clock.SetTime(
          var x = time.Length;
          throw new NotImplementedException("set time is not implemented yet");
        });

      config.AddHandler("POST", "/sys/time/sync", "sync time with NTP")
        .ReturnsJson()
        .HandledBy(() =>
        {
          RealTimeClock.Instance.UpdateFromNTP();
          var status = new JsonObject();
          status.Add("time", DateTime.Now);
          return status;
        });

      config.AddHandler("POST", "/sys/reboot", "reboot the device")
        .SetNotes("This will reboot the device and not return")
        .ReturnsNothing()
        .HandledBy(() => MainBoard.Reboot());


      config.AddHandler("GET", "/hw/doors/{doorname}", "get status for the door")
        .ReturnsJson()
        .HandledBy((doorname) =>
          {
            var door = machinery.LookupDoorByName(doorname);
            var status = new JsonObject();
            status.Add("name", door.Name);
            status.Add("status", EnumUtil.DoorStatusTostring(door.Status));
            return status;
          });

      config.AddHandler("POST", "/hw/doors/{doorname}/open", "open the door completely")
        .ReturnsNothing()
        .HandledBy((doorname) =>
          {
            var door = machinery.LookupDoorByName(doorname);
            machinery.Sequencer.Enqueue(() => door.OpenCompletely());
          });

      config.AddHandler("POST", "/hw/doors/{doorname}/close", "close the door completely")
        .ReturnsNothing()
        .HandledBy((doorname) =>
          {
            var door = machinery.LookupDoorByName(doorname);
            machinery.Sequencer.Enqueue(() => door.CloseCompletely());
          });

      config.AddHandler("POST", "/hw/doors/{doorname}/moveup/{millisec}", "move the door up")
        .ReturnsNothing()
        .HandledBy((doorname, millisec) =>
          {
            var door = machinery.LookupDoorByName(doorname);
            var msec = int.Parse(millisec);
            machinery.Sequencer.Enqueue(() => door.MoveUp(msec));
          });

      config.AddHandler("POST", "/hw/doors/{doorname}/movedown/{millisec}", "move the door down")
        .ReturnsNothing()
        .HandledBy((doorname, millisec) =>
          {
            var door = machinery.LookupDoorByName(doorname);
            var msec = int.Parse(millisec);
            machinery.Sequencer.Enqueue(() => door.MoveDown(msec));
          });

      config.AddHandler("POST", "/hw/doors/{doorname}/stop", "stop moving the door")
        .ReturnsNothing()
        .HandledBy((doorname) =>
          {
            var door = machinery.LookupDoorByName(doorname);
            door.StopMoving(); // Stop immediately - don't go through sequencer!
          });

      config.AddHandler("GET", "/hw/relays/{relayname}", "get state of relay")
        .ReturnsJson()
        .HandledBy((relayname) =>
          {
            var relay = machinery.LookupRelayByName(relayname);
            var status = new JsonObject();
            status.Add("name", relay.Name);
            status.Add("on", relay.On);
            return status;
          });

      config.AddHandler("PUT", "/hw/relays/{relayname}/on", "turn relay on")
        .ReturnsNothing()
        .HandledBy((relayname) =>
          {
            var relay = machinery.LookupRelayByName(relayname);
            relay.On = true;
          });

      config.AddHandler("PUT", "/hw/relays/{relayname}/off", "turn relay off")
        .ReturnsNothing()
        .HandledBy((relayname) =>
          {
            var relay = machinery.LookupRelayByName(relayname);
            relay.On = false;
          });

      config.AddHandler("POST", "/admin/log/clear", "clear the entire log")
        .ReturnsNothing()
        .HandledBy(() =>
          {
            Logger.Instance.Full.Clear();
            Logger.Instance.Errors.Clear();
          });

      config.AddHandler("GET", "/admin/log/full", "get full log")
        .ReturnsStream()
        .HandledBy((context) =>
          {
            context.Response.OutputStream.WriteByte((byte)'[');
            foreach (var line in Logger.Instance.Full.GetLines())
            {
              var b = System.Text.Encoding.UTF8.GetBytes(Json.NETMF.JsonSerializer.SerializeObject(line));
              context.Response.OutputStream.Write(b, 0, b.Length);
              context.Response.OutputStream.WriteByte((byte)',');
            }
            context.Response.OutputStream.WriteByte((byte)']');
          });

      config.AddHandler("GET", "/admin/log/errors", "get error log")
        .ReturnsJson()
        .HandledBy(() =>
          {
            return Logger.Instance.Errors.GetLinesAsJson();
          });

      config.AddHandler("GET", "/config/schedule", "get the schedule")
        .ReturnsJson()
        .HandledBy(() => doorScheduler.GetScheduleAsJson());

      var credentials = CredentialValidatorFactory.CreateSimpleValidator("Bootstrapper", "admin", "hnsefyk");
      var webService = new WebService(c_servicePort, credentials, config);

      string prefix = Name + ": ";
      webService.Logging.OnLogInfo += message => Logger.Instance.LogInfo(prefix + message);
      webService.Logging.OnLogError += message => Logger.Instance.LogError(prefix + message);
      webService.Logging.OnLogException += (message, ex) => Logger.Instance.LogException(prefix + message, ex);

      webService.Start();
    }