aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Video/DirectSampleGrabber.cs
blob: 36e1482676a29caa0d97ba4edc0db3da4f2c0d5d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
using DirectShowLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Tango.Video.DirectShow
{
    internal class SampleGrabberImpl : ISampleGrabberCB
    {
        #region delegates
        public delegate int BufferCallback(double SampleTime, IntPtr pBuffer, int BufferLen);
        public delegate int BufferCallback2(double sampleTime, IMediaSample pSample);
        #endregion

        #region Members

        readonly BufferCallback _callback;
        readonly BufferCallback2 _callback2;
        #endregion

        #region Constructor
        public SampleGrabberImpl(BufferCallback callback, BufferCallback2 callback2 = null)
        {
            _callback = callback;
            _callback2 = callback2;
        }
        #endregion

        #region ISampleGrabberCB Members

        public int BufferCB(double SampleTime, IntPtr pBuffer, int BufferLen)
        {
            if (_callback != null)
            {
                return _callback(SampleTime, pBuffer, BufferLen);
            }
            return 0;
        }

        public int SampleCB(double SampleTime, IMediaSample pSample)
        {
            if (_callback2 != null)
            {
                return _callback2(SampleTime, pSample);
            }
            Marshal.ReleaseComObject(pSample);
            return 0;
        }

        #endregion
    }
}
; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
using CommandLine;
using Ionic.Zip;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tango.AdvancedInstaller;
using Tango.Core;
using Tango.Core.Cryptography;
using Tango.Core.Helpers;
using Tango.Git;
using Tango.MachineStudio.Common.Web;
using Tango.Transport.Web;
using Tango.Web;

namespace Tango.MachineStudio.Common.Publish
{
    public class MachineStudioPublisher : ExtendedObject
    {
        private MachineStudioWebClient _client;

        /// <summary>
        /// Occurs on publish progress.
        /// </summary>
        public event EventHandler<PublishProgressEventArgs> PublishProgress;

        private PublishOptions _options;
        /// <summary>
        /// Gets or sets the publish options.
        /// </summary>
        public PublishOptions Options
        {
            get { return _options; }
            set { _options = value; RaisePropertyChangedAuto(); }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MachineStudioPublisher"/> class.
        /// </summary>
        public MachineStudioPublisher()
        {
            _client = new MachineStudioWebClient();
            Options = new PublishOptions();
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MachineStudioPublisher"/> class.
        /// </summary>
        /// <param name="publishOptions">The publish options.</param>
        public MachineStudioPublisher(PublishOptions publishOptions) : this()
        {
            Options = publishOptions;
        }

        /// <summary>
        /// Gets the latest version.
        /// </summary>
        /// <returns></returns>
        public async Task<String> GetRemoteVersion()
        {
            _client.Environment = Options.Environment;
            var response = await _client.GetLatestVersion(new LatestVersionRequest());
            return response.Version;
        }

        /// <summary>
        /// Gets the latest version.
        /// </summary>
        /// <returns></returns>
        public async Task<String> GetRemoteVersion(DeploymentSlot environment)
        {
            _client.Environment = environment;
            var response = await _client.GetLatestVersion(new LatestVersionRequest());
            return response.Version;
        }

        /// <summary>
        /// Gets the latest version.
        /// </summary>
        /// <returns></returns>
        public String GetLocalVersion()
        {
            return FileVersionInfo.GetVersionInfo(GetMachineStudioExecutablePath()).ProductVersion;
        }

        /// <summary>
        /// Gets the machine studio executable path.
        /// </summary>
        /// <returns></returns>
        public String GetMachineStudioExecutablePath()
        {
            String appPath = Path.Combine(Options.GetApplicationPath(), "Tango.MachineStudio.UI.exe");
            return appPath;
        }

        /// <summary>
        /// Login to machine service and returns an access token.
        /// </summary>
        /// <returns></returns>
        private Task Login()
        {
            return Task.Factory.StartNew(() =>
            {
                return _client.Login(new LoginRequest()
                {
                    Email = Options.Email,
                    Password = Options.Password,
                    Version = GetLocalVersion(),
                }).Result;
            });
        }

        /// <summary>
        /// Publish a machine studio version using the specified <see cref="Options"/>.
        /// </summary>
        /// <returns></returns>
        public Task Publish()
        {
            _client.Environment = Options.Environment;

            String appPath = GetMachineStudioExecutablePath();
            String folder = Options.GetApplicationPath();

            if (!File.Exists(appPath))
            {
                throw new FileNotFoundException($"Could not locate the machine studio executable at {appPath}.");
            }

            if (!String.IsNullOrWhiteSpace(Options.InstallerProject))
            {
                if (!File.Exists(Options.InstallerProject))
                {
                    throw new FileNotFoundException($"Installer project not found at '{Options.InstallerProject}'.");
                }

                if (!Directory.Exists(Options.InstallerOutputFolder))
                {
                    throw new DirectoryNotFoundException($"Installer output folder does not exists '{Options.InstallerOutputFolder}'.");
                }
            }

            String tempFile = TemporaryManager.CreateFile();

            return Task.Factory.StartNew(() =>
            {
                try
                {
                    OnPublishProgress(0, 100, $"Logging in to machine service at {Options.Environment.ToAddress()}...");
                    Login().Wait();

                    OnPublishProgress(0, 100, $"Fetching remote version from {Options.Environment.ToAddress()}...");

                    String remote_version = GetRemoteVersion().Result;
                    String local_version = GetLocalVersion();

                    OnPublishProgress(0, 100, $"Remote version: {remote_version}");
                    OnPublishProgress(0, 100, $"Local version: {local_version}");

                    if (Version.Parse(local_version) <= Version.Parse(remote_version))
                    {
                        throw new InvalidOperationException($"The local version '{local_version}' is not greater than the remote version '{remote_version}'.");
                    }

                    if (Options.CreateTag)
                    {
                        String repoPath = Path.GetFullPath("../../../../../");
                        using (GitRepositoryManager git = new GitRepositoryManager(repoPath, Options.Email, Options.PersonalAccessToken))
                        {
                            OnPublishProgress(0, 100, "Checking repository changes...");
                            int changes = git.GetChanges().Count;
                            if (changes > 0)
                            {
                                throw new InvalidOperationException($"There are {changes} uncommitted changes on the repository. Please commit and push all changes before creating the Tag");
                            }

                            OnPublishProgress(0, 100, "Checking outgoing commits...");
                            int commits = git.GetOutgoingCommits().Count;
                            if (commits > 0)
                            {
                                throw new InvalidOperationException($"There are {commits} outgoing commits on the repository. Please push all commits before creating the Tag");
                            }

                            String tagVersion = System.Version.Parse(GetLocalVersion()).ToString(3);
                            String tagName = $"Machine_Studio_v{tagVersion}";
                            String tagDescription = $"Snapshot of Machine Studio v{tagVersion}";

                            git.Progress += (x, e) =>
                            {
                                OnPublishProgress(e.Progress.Value, e.Progress.Maximum, $"Pushing Tag '{tagName}'...");
                            };

                            OnPublishProgress(0, 100, $"Creating Tag '{tagName}'...");

                            git.CreatePushTag(tagName, tagDescription, "Roy Ben Shabat");
                        }
                    }

                    OnPublishProgress(0, 100, $"Requesting version upload...");

                    var response = _client.UploadVersion(new UploadVersionRequest()
                    {
                        Version = local_version,
                        Comments = Options.Comments,
                        WithInstaller = !String.IsNullOrWhiteSpace(Options.InstallerProject),
                    }).Result;

                    if (!String.IsNullOrWhiteSpace(Options.InstallerProject))
                    {
                        String output_folder = Options.InstallerOutputFolder;
                        OnPublishProgress(0, 100, $"Building installer project...");
                        InstallerBuilder installerBuilder = new InstallerBuilder(Options.InstallerProject);
                        String installer_name = $"Machine Studio Installer_v{Version.Parse(local_version).ToString(3)}.exe";
                        String output_file = Path.Combine(output_folder, installer_name);
                        installerBuilder.Build(local_version, output_file).Wait();

                        Thread.Sleep(5000);

                        OnPublishProgress(0, 100, $"Uploading installer '{installer_name}'...");

                        using (StorageBlobUploader uploader = new StorageBlobUploader(response.InstallerBlobAddress, output_file))
                        {
                            uploader.Progress += (x, e) =>
                            {
                                OnPublishProgress(e.Current, e.Total, $"Uploading installer {(((double)e.Current / (double)e.Total) * 100d).ToString("0.0")}%...", true);
                            };

                            uploader.Upload().Wait();
                        }
                    }

                    OnPublishProgress(0, 100, $"Starting version packaging...");

                    using (ZipFile zip = new ZipFile())
                    {
                        foreach (var directory in Directory.GetDirectories(folder))
                        {
                            zip.AddDirectory(directory, $"/{Path.GetFileName(directory)}");
                        }

                        var files = Directory.GetFiles(folder, "*.*", SearchOption.TopDirectoryOnly).ToList();

                        foreach (var file in files)
                        {
                            zip.AddFile(file, "/");
                        }

                        zip.SaveProgress += (x, e) =>
                        {
                            if (e.EventType == ZipProgressEventType.Saving_BeforeWriteEntry)
                            {
                                OnPublishProgress(e.EntriesSaved + 1, e.EntriesTotal, $"Compressing files {(((double)(e.EntriesSaved + 1) / (double)e.EntriesTotal) * 100d).ToString("0.0")}%...", true);
                            }
                        };

                        zip.ParallelDeflateThreshold = -1;
                        zip.Save(tempFile);
                    }

                    OnPublishProgress(0, 100, $"Starting version upload...");

                    using (StorageBlobUploader uploader = new StorageBlobUploader(response.BlobAddress, tempFile))
                    {
                        uploader.Progress += (x, e) =>
                        {
                            OnPublishProgress(e.Current, e.Total, $"Uploading version {(((double)e.Current / (double)e.Total) * 100d).ToString("0.0")}%...", true);
                        };

                        uploader.Upload().Wait();
                    }

                    OnPublishProgress(100, 100, $"Finalizing version upload...");

                    _client.NotifyVersionUploadCompleted(new UploadCompletedRequest()
                    {
                        Token = response.Token,
                    }).Wait();

                    remote_version = GetRemoteVersion().Result;
                    local_version = GetLocalVersion();

                    OnPublishProgress(0, 0, $"Remote version: {remote_version}");
                    OnPublishProgress(0, 0, $"Local version: {local_version}");

                    if (remote_version != local_version)
                    {
                        throw new InvalidOperationException("The remote version does not seems to have been updated.");
                    }

                    OnPublishProgress(0, 0, "Version published successfully.");
                }
                catch (Exception ex)
                {
                    OnPublishProgress(0, 100, $"Failed: {ex.Message}");
                    throw ex;
                }
                finally
                {
                    PathHelper.TryDeleteFile(tempFile);
                }
            });
        }

        /// <summary>
        /// Raises the publish progress event.
        /// </summary>
        /// <param name="progress">The progress.</param>
        /// <param name="total">The total.</param>
        /// <param name="message">The message.</param>
        protected virtual void OnPublishProgress(double progress, double total, String message, bool singleLine = false)
        {
            PublishProgress?.Invoke(this, new PublishProgressEventArgs()
            {
                Progress = progress,
                Total = total,
                Message = message,
                SingleLineRecommended = singleLine,
            });
        }
    }
}