//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//------------------------------------------------------------------------------
namespace Microsoft.Samples.Kinect.WebserverBasics
{
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Windows;
using Microsoft.Kinect.Toolkit;
using Microsoft.Samples.Kinect.Webserver;
///
/// Interaction logic for MainWindow.
///
public partial class MainWindow : Window
{
public static readonly DependencyProperty IsStartedProperty = DependencyProperty.Register(
"IsStarted", typeof(bool), typeof(MainWindow), new PropertyMetadata(false));
public static readonly DependencyProperty ErrorTextProperty = DependencyProperty.Register(
"ErrorText", typeof(string), typeof(MainWindow), new PropertyMetadata(string.Empty));
///
/// Name (URI sub-path) to be used by clients to refer to the default kinect sensor.
///
private const string DefaultSensorChooserName = "default";
///
/// Name of main page for web sample.
///
private const string SamplePageName = "playing-in-the-street.html";
///
/// Character used to separate origins in list of origins allowed to access this server.
///
private const char AllowedOriginSeparator = ',';
///
/// Component that manages finding a Kinect sensor
///
private readonly KinectSensorChooser sensorChooser = new KinectSensorChooser();
///
/// Webserver that handles requests from web clients.
///
private readonly KinectWebserver webserver = new KinectWebserver();
///
/// Error buffer listener used to update error text in UI.
///
private readonly RecentEventBufferTraceListener errorBufferListener;
///
/// Initializes a new instance of the MainWindow class.
///
public MainWindow()
{
this.InitializeComponent();
if (!IsSupportedOsVersion(Environment.OSVersion))
{
MessageBox.Show(
Properties.Resources.SystemVersionNotSupportedMessage,
Properties.Resources.SystemVersionNotSupportedCaption,
MessageBoxButton.OK);
Application.Current.Shutdown();
}
this.DataContext = this;
this.errorBufferListener = Trace.Listeners["errorBufferListener"] as RecentEventBufferTraceListener;
if (this.errorBufferListener != null)
{
this.errorBufferListener.RecentEventBufferChanged += this.ErrorBufferListenerOnChanged;
}
Uri originUri;
try
{
originUri = new Uri(Properties.Settings.Default.OriginUri.Trim());
}
catch (UriFormatException)
{
Trace.TraceError("Invalid format for listening origin: \"{0}\"", Properties.Settings.Default.OriginUri);
// If we can't listen on origin, we can't serve any data whatsover, so there is no sense in continuing
// setup
return;
}
this.webserver.SensorChooserMap.Add(DefaultSensorChooserName, this.sensorChooser);
if (!string.IsNullOrWhiteSpace(Properties.Settings.Default.FileRootDirectory))
{
this.webserver.FileServerRootDirectory = Properties.Settings.Default.FileRootDirectory;
try
{
this.RootDirectoryTextRun.Text = Path.GetFullPath(Properties.Settings.Default.FileRootDirectory);
}
catch (ArgumentException e)
{
this.ShowNotServingFilesUi();
Trace.TraceError("Exception encountered while parsing root directory for serving files:\n{0}", e);
}
}
else
{
this.ShowNotServingFilesUi();
}
this.webserver.OriginUri = originUri;
if (!string.IsNullOrWhiteSpace(Properties.Settings.Default.AccessControlAllowedOrigins))
{
foreach (var origin in Properties.Settings.Default.AccessControlAllowedOrigins.Split(AllowedOriginSeparator))
{
try
{
originUri = new Uri(origin.Trim());
}
catch (UriFormatException)
{
Trace.TraceError("Invalid format for access control allowed origin: {0}", origin);
continue;
}
this.webserver.AccessControlAllowedOrigins.Add(originUri);
}
}
//// TODO: Optionally add factories here for custom handlers:
//// this.webserver.SensorStreamHandlerFactories.Add(new MyCustomSensorStreamHandlerFactory());
//// Your custom factory would implement ISensorStreamHandlerFactory, in which the
//// CreateHandler method would return a class derived from SensorStreamHandlerBase
//// which overrides one or more of its virtual methods.
this.webserver.Started += (server, args) => this.IsStarted = true;
this.webserver.Stopped += (server, args) => this.IsStarted = false;
}
///
/// Gets the KinectSensorChooser component
///
public KinectSensorChooser KinectSensorChooser
{
get { return this.sensorChooser; }
}
///
/// true if server has started listening, false otherwise.
///
public bool IsStarted
{
get
{
return (bool)this.GetValue(IsStartedProperty);
}
set
{
this.SetValue(IsStartedProperty, value);
}
}
///
/// Error text to display in UI.
///
public string ErrorText
{
get
{
return (string)this.GetValue(ErrorTextProperty);
}
set
{
this.SetValue(ErrorTextProperty, value);
}
}
///
/// Determine if running this application is supported in the specified operating
/// system version.
///
///
/// Operating system version information.
///
///
/// true if running this application is supported in the specified operating system.
/// false otherwise.
///
private static bool IsSupportedOsVersion(OperatingSystem systemInfo)
{
const int MinimumMajorVersion = 6;
const int MinimumMinorVersion = 2;
return (systemInfo.Version.Major > MinimumMajorVersion)
|| ((systemInfo.Version.Major == MinimumMajorVersion) && (systemInfo.Version.Minor >= MinimumMinorVersion));
}
///
/// Start web server, reporting an error to trace listeners if exception is encountered.
///
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Server application should never crash. Errors are reported in web server UI instead.")]
private void StartWebserver()
{
try
{
this.webserver.Start();
}
catch (Exception e)
{
Trace.TraceError("Unable to start server due to exception:\n{0}", e);
}
}
///
/// Stop web server, reporting an error to trace listeners if exception is encountered.
///
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Server application should never crash. Errors are reported in web server UI instead.")]
private void StopWebserver()
{
try
{
this.webserver.Stop();
}
catch (Exception e)
{
Trace.TraceError("Unable to stop server due to exception:\n{0}", e);
}
}
///
/// Show UI appropriate for when we're not serving static files.
///
private void ShowNotServingFilesUi()
{
this.ServingFilesText.Visibility = Visibility.Collapsed;
this.OpenBrowserText.Visibility = Visibility.Collapsed;
this.NotServingFilesText.Visibility = Visibility.Visible;
}
private void WindowLoaded(object sender, RoutedEventArgs e)
{
this.sensorChooser.Start();
this.StartWebserver();
}
private void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
this.StopWebserver();
}
private void StartButtonOnClick(object sender, RoutedEventArgs e)
{
this.StartWebserver();
}
private void StopButtonOnClick(object sender, RoutedEventArgs e)
{
this.StopWebserver();
}
private void ErrorBufferListenerOnChanged(object sender, EventArgs e)
{
this.Dispatcher.BeginInvoke((Action)(() => this.ErrorText = this.errorBufferListener.RecentEventBuffer));
}
///
/// Event handler for UriLink's Click event.
///
///
/// Object triggering the event.
///
///
/// Event arguments.
///
private void UriLinkOnClick(object sender, RoutedEventArgs e)
{
// Shell execute the URI of sample page to open in default browser
var samplePageUri = this.webserver.OriginUri.ConcatenateSegments(this.webserver.FileServerBasePath, SamplePageName);
if (samplePageUri == null)
{
return;
}
var startInfo = new ProcessStartInfo(samplePageUri.ToString()) { UseShellExecute = true };
using (var process = new Process())
{
process.StartInfo = startInfo;
process.Start();
}
}
}
}