Browse Source

Implemented upload of usage data.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4939 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 16 years ago
parent
commit
864ebd6793
  1. 4
      src/AddIns/Misc/UsageDataCollector/UsageDataCollector.AddIn/AnalyticsMonitor.cs
  2. 150
      src/AddIns/Misc/UsageDataCollector/UsageDataCollector/Reference.cs
  3. 9
      src/AddIns/Misc/UsageDataCollector/UsageDataCollector/UsageDataCollector.csproj
  4. 39
      src/AddIns/Misc/UsageDataCollector/UsageDataCollector/UsageDataMessage.cs
  5. 44
      src/AddIns/Misc/UsageDataCollector/UsageDataCollector/UsageDataUploader.cs
  6. 28
      src/AddIns/Misc/UsageDataCollector/UsageDataCollector/app.config

4
src/AddIns/Misc/UsageDataCollector/UsageDataCollector.AddIn/AnalyticsMonitor.cs

@ -19,6 +19,8 @@ namespace ICSharpCode.UsageDataCollector @@ -19,6 +19,8 @@ namespace ICSharpCode.UsageDataCollector
/// </summary>
public sealed class AnalyticsMonitor : IAnalyticsMonitor
{
const string UploadUrl = "http://build.sharpdevelop.net/udc.upload/uploadusagedata.svc";
public static readonly AnalyticsMonitor Instance = new AnalyticsMonitor();
public static bool EnabledIsUndecided {
@ -99,7 +101,7 @@ namespace ICSharpCode.UsageDataCollector @@ -99,7 +101,7 @@ namespace ICSharpCode.UsageDataCollector
}
if (sessionOpened) {
UsageDataUploader uploader = new UsageDataUploader(dbFileName);
ThreadPool.QueueUserWorkItem(delegate { uploader.StartUpload(); });
ThreadPool.QueueUserWorkItem(delegate { uploader.StartUpload(UploadUrl); });
}
}

150
src/AddIns/Misc/UsageDataCollector/UsageDataCollector/Reference.cs

@ -0,0 +1,150 @@ @@ -0,0 +1,150 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.20728.1
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ICSharpCode.UsageDataCollector.Service {
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="Service.IUDCUploadService")]
internal interface IUDCUploadService {
// CODEGEN: Generating message contract since the wrapper name (UDCUploadRequest) of message UDCUploadRequest does not match the default value (UploadUsageData)
[System.ServiceModel.OperationContractAttribute(IsOneWay=true, Action="http://tempuri.org/IUDCUploadService/UploadUsageData")]
void UploadUsageData(ICSharpCode.UsageDataCollector.Service.UDCUploadRequest request);
[System.ServiceModel.OperationContractAttribute(IsOneWay=true, AsyncPattern=true, Action="http://tempuri.org/IUDCUploadService/UploadUsageData")]
System.IAsyncResult BeginUploadUsageData(ICSharpCode.UsageDataCollector.Service.UDCUploadRequest request, System.AsyncCallback callback, object asyncState);
void EndUploadUsageData(System.IAsyncResult result);
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="UDCUploadRequest", WrapperNamespace="http://tempuri.org/", IsWrapped=true)]
internal partial class UDCUploadRequest {
[System.ServiceModel.MessageHeaderAttribute(Namespace="http://tempuri.org/")]
public string ApplicationKey;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://tempuri.org/", Order=0)]
public System.IO.Stream UsageData;
public UDCUploadRequest() {
}
public UDCUploadRequest(string ApplicationKey, System.IO.Stream UsageData) {
this.ApplicationKey = ApplicationKey;
this.UsageData = UsageData;
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
internal interface IUDCUploadServiceChannel : ICSharpCode.UsageDataCollector.Service.IUDCUploadService, System.ServiceModel.IClientChannel {
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
internal partial class UDCUploadServiceClient : System.ServiceModel.ClientBase<ICSharpCode.UsageDataCollector.Service.IUDCUploadService>, ICSharpCode.UsageDataCollector.Service.IUDCUploadService {
private BeginOperationDelegate onBeginUploadUsageDataDelegate;
private EndOperationDelegate onEndUploadUsageDataDelegate;
private System.Threading.SendOrPostCallback onUploadUsageDataCompletedDelegate;
public UDCUploadServiceClient() {
}
public UDCUploadServiceClient(string endpointConfigurationName) :
base(endpointConfigurationName) {
}
public UDCUploadServiceClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public UDCUploadServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public UDCUploadServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress) {
}
public event System.EventHandler<System.ComponentModel.AsyncCompletedEventArgs> UploadUsageDataCompleted;
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
void ICSharpCode.UsageDataCollector.Service.IUDCUploadService.UploadUsageData(ICSharpCode.UsageDataCollector.Service.UDCUploadRequest request) {
base.Channel.UploadUsageData(request);
}
public void UploadUsageData(string ApplicationKey, System.IO.Stream UsageData) {
ICSharpCode.UsageDataCollector.Service.UDCUploadRequest inValue = new ICSharpCode.UsageDataCollector.Service.UDCUploadRequest();
inValue.ApplicationKey = ApplicationKey;
inValue.UsageData = UsageData;
((ICSharpCode.UsageDataCollector.Service.IUDCUploadService)(this)).UploadUsageData(inValue);
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
System.IAsyncResult ICSharpCode.UsageDataCollector.Service.IUDCUploadService.BeginUploadUsageData(ICSharpCode.UsageDataCollector.Service.UDCUploadRequest request, System.AsyncCallback callback, object asyncState) {
return base.Channel.BeginUploadUsageData(request, callback, asyncState);
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
public System.IAsyncResult BeginUploadUsageData(string ApplicationKey, System.IO.Stream UsageData, System.AsyncCallback callback, object asyncState) {
ICSharpCode.UsageDataCollector.Service.UDCUploadRequest inValue = new ICSharpCode.UsageDataCollector.Service.UDCUploadRequest();
inValue.ApplicationKey = ApplicationKey;
inValue.UsageData = UsageData;
return ((ICSharpCode.UsageDataCollector.Service.IUDCUploadService)(this)).BeginUploadUsageData(inValue, callback, asyncState);
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
public void EndUploadUsageData(System.IAsyncResult result) {
base.Channel.EndUploadUsageData(result);
}
private System.IAsyncResult OnBeginUploadUsageData(object[] inValues, System.AsyncCallback callback, object asyncState) {
string ApplicationKey = ((string)(inValues[0]));
System.IO.Stream UsageData = ((System.IO.Stream)(inValues[1]));
return this.BeginUploadUsageData(ApplicationKey, UsageData, callback, asyncState);
}
private object[] OnEndUploadUsageData(System.IAsyncResult result) {
this.EndUploadUsageData(result);
return null;
}
private void OnUploadUsageDataCompleted(object state) {
if ((this.UploadUsageDataCompleted != null)) {
InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));
this.UploadUsageDataCompleted(this, new System.ComponentModel.AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
}
}
public void UploadUsageDataAsync(string ApplicationKey, System.IO.Stream UsageData) {
this.UploadUsageDataAsync(ApplicationKey, UsageData, null);
}
public void UploadUsageDataAsync(string ApplicationKey, System.IO.Stream UsageData, object userState) {
if ((this.onBeginUploadUsageDataDelegate == null)) {
this.onBeginUploadUsageDataDelegate = new BeginOperationDelegate(this.OnBeginUploadUsageData);
}
if ((this.onEndUploadUsageDataDelegate == null)) {
this.onEndUploadUsageDataDelegate = new EndOperationDelegate(this.OnEndUploadUsageData);
}
if ((this.onUploadUsageDataCompletedDelegate == null)) {
this.onUploadUsageDataCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnUploadUsageDataCompleted);
}
base.InvokeAsync(this.onBeginUploadUsageDataDelegate, new object[] {
ApplicationKey,
UsageData}, this.onEndUploadUsageDataDelegate, this.onUploadUsageDataCompletedDelegate, userState);
}
}
}

9
src/AddIns/Misc/UsageDataCollector/UsageDataCollector/UsageDataCollector.csproj

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
<OutputType>Library</OutputType>
<RootNamespace>ICSharpCode.UsageDataCollector</RootNamespace>
<AssemblyName>UsageDataCollector</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<OutputPath>..\..\..\..\..\AddIns\AddIns\Misc\UsageDataCollector\</OutputPath>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
@ -43,21 +43,26 @@ @@ -43,21 +43,26 @@
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Data.SQLite">
<HintPath>..\..\..\Libraries\SQLite\System.Data.SQLite.dll</HintPath>
<HintPath>..\..\..\..\Libraries\SQLite\System.Data.SQLite.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Runtime.Serialization">
<RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference>
<Reference Include="System.ServiceModel" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\..\Main\GlobalAssemblyInfo.cs">
<Link>GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Reference.cs" />
<Compile Include="UsageDataMessage.cs" />
<Compile Include="UsageDataSessionWriter.cs" />
<Compile Include="UsageDataUploader.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="app.config" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

39
src/AddIns/Misc/UsageDataCollector/UsageDataCollector/UsageDataMessage.cs

@ -9,13 +9,13 @@ using System; @@ -9,13 +9,13 @@ using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace ICSharpCode.UsageDataCollector
namespace ICSharpCode.UsageDataCollector.DataContract
{
/// <summary>
/// Represents a message used to send data to the server.
/// </summary>
[DataContract]
sealed class UsageDataMessage
public sealed class UsageDataMessage
{
/// <summary>
/// Unique identifier per user.
@ -23,10 +23,17 @@ namespace ICSharpCode.UsageDataCollector @@ -23,10 +23,17 @@ namespace ICSharpCode.UsageDataCollector
/// </summary>
[DataMember]
public Guid UserID;
/// <summary>
/// Gets the sessions stored in this message.
/// </summary>
[DataMember]
public List<UsageDataSession> Sessions = new List<UsageDataSession>();
/// <summary>
/// Finds the session with the specified session ID.
/// </summary>
/// <exception cref="ArgumentException">No session with the specified ID was found.</exception>
public UsageDataSession FindSession(long sessionID)
{
foreach (UsageDataSession s in Sessions) {
@ -37,8 +44,11 @@ namespace ICSharpCode.UsageDataCollector @@ -37,8 +44,11 @@ namespace ICSharpCode.UsageDataCollector
}
}
/// <summary>
/// A UsageData session.
/// </summary>
[DataContract]
sealed class UsageDataSession
public sealed class UsageDataSession
{
/// <summary>
/// ID of the session, usually unique per user (unless the user restores a backup of the database).
@ -60,12 +70,21 @@ namespace ICSharpCode.UsageDataCollector @@ -60,12 +70,21 @@ namespace ICSharpCode.UsageDataCollector
[DataMember]
public DateTime? EndTime;
/// <summary>
/// List of environment properties associated with the session.
/// </summary>
[DataMember]
public List<UsageDataEnvironmentProperty> EnvironmentProperties = new List<UsageDataEnvironmentProperty>();
/// <summary>
/// List of feature uses associated with the session.
/// </summary>
[DataMember]
public List<UsageDataFeatureUse> FeatureUses = new List<UsageDataFeatureUse>();
/// <summary>
/// List of exceptions associated with the session.
/// </summary>
[DataMember]
public List<UsageDataException> Exceptions = new List<UsageDataException>();
}
@ -76,11 +95,17 @@ namespace ICSharpCode.UsageDataCollector @@ -76,11 +95,17 @@ namespace ICSharpCode.UsageDataCollector
/// or have multiple OS installations pointing to the same database (e.g. when SharpDevelop is used on an USB stick).
/// </summary>
[DataContract]
sealed class UsageDataEnvironmentProperty
public sealed class UsageDataEnvironmentProperty
{
/// <summary>
/// Name of the property.
/// </summary>
[DataMember]
public string Name;
/// <summary>
/// Value of the property.
/// </summary>
[DataMember]
public string Value;
}
@ -89,7 +114,7 @@ namespace ICSharpCode.UsageDataCollector @@ -89,7 +114,7 @@ namespace ICSharpCode.UsageDataCollector
/// Represents a feature being used.
/// </summary>
[DataContract]
sealed class UsageDataFeatureUse
public sealed class UsageDataFeatureUse
{
/// <summary>
/// The time when the feature was used.
@ -124,7 +149,7 @@ namespace ICSharpCode.UsageDataCollector @@ -124,7 +149,7 @@ namespace ICSharpCode.UsageDataCollector
/// The exception message might e.g. contain names of the file the user is working on.
/// </summary>
[DataContract]
sealed class UsageDataException
public sealed class UsageDataException
{
/// <summary>
/// The time when the exception occurred.

44
src/AddIns/Misc/UsageDataCollector/UsageDataCollector/UsageDataUploader.cs

@ -13,8 +13,13 @@ using System.IO; @@ -13,8 +13,13 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Xml;
using ICSharpCode.UsageDataCollector.DataContract;
using ICSharpCode.UsageDataCollector.Service;
namespace ICSharpCode.UsageDataCollector
{
/// <summary>
@ -70,7 +75,20 @@ namespace ICSharpCode.UsageDataCollector @@ -70,7 +75,20 @@ namespace ICSharpCode.UsageDataCollector
/// </summary>
/// <exception cref="IncompatibleDatabaseException">The database version is not compatible with this
/// version of the AnalyticsSessionWriter.</exception>
public void StartUpload()
public void StartUpload(string uploadUrl)
{
EndpointAddress epa = new EndpointAddress(uploadUrl);
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.None;
StartUpload(binding, epa);
}
/// <summary>
/// Starts the upload of the usage data.
/// </summary>
/// <exception cref="IncompatibleDatabaseException">The database version is not compatible with this
/// version of the AnalyticsSessionWriter.</exception>
public void StartUpload(Binding binding, EndpointAddress endpoint)
{
UsageDataMessage message;
using (SQLiteConnection connection = OpenConnection()) {
@ -85,15 +103,32 @@ namespace ICSharpCode.UsageDataCollector @@ -85,15 +103,32 @@ namespace ICSharpCode.UsageDataCollector
}
}
if (message != null) {
string commaSeparatedSessionIDList = GetCommaSeparatedIDList(message.Sessions);
DataContractSerializer serializer = new DataContractSerializer(typeof(UsageDataMessage));
using (FileStream fs = new FileStream(Path.Combine(Path.GetTempPath(), "SharpDevelopUsageData.xml.gz"), FileMode.Create, FileAccess.Write)) {
using (GZipStream zip = new GZipStream(fs, CompressionMode.Compress)) {
byte[] data;
using (MemoryStream ms = new MemoryStream()) {
using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress)) {
serializer.WriteObject(zip, message);
}
data = ms.ToArray();
}
message = null;
File.WriteAllBytes(Path.Combine(Path.GetTempPath(), "SharpDevelopUsageData.xml.gz"), data);
UDCUploadServiceClient client = new UDCUploadServiceClient(binding, endpoint);
client.BeginUploadUsageData("sharpdevelop", new MemoryStream(data),
ar => UsageDataUploaded(ar, client, commaSeparatedSessionIDList), null);
}
}
void UsageDataUploaded(IAsyncResult result, UDCUploadServiceClient client, string commaSeparatedSessionIDList)
{
client.EndUploadUsageData(result);
RemoveUploadedData(commaSeparatedSessionIDList);
}
Version expectedDBVersion = new Version(1, 0, 1);
void CheckDatabaseVersion(SQLiteConnection connection)
@ -224,9 +259,8 @@ namespace ICSharpCode.UsageDataCollector @@ -224,9 +259,8 @@ namespace ICSharpCode.UsageDataCollector
/// <summary>
/// Removes the data that was successfully uploaded and sets the 'lastUpload' property.
/// </summary>
void RemoveUploadedData(IEnumerable<UsageDataSession> sessions)
void RemoveUploadedData(string commaSeparatedSessionIDList)
{
string commaSeparatedSessionIDList = GetCommaSeparatedIDList(sessions);
using (SQLiteConnection connection = OpenConnection()) {
using (SQLiteTransaction transaction = connection.BeginTransaction()) {
using (SQLiteCommand cmd = connection.CreateCommand()) {

28
src/AddIns/Misc/UsageDataCollector/UsageDataCollector/app.config

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IUDCUploadService" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Mtom" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://build.sharpdevelop.net/udc.upload/uploadusagedata.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IUDCUploadService"
contract="Service.IUDCUploadService" name="BasicHttpBinding_IUDCUploadService" />
</client>
</system.serviceModel>
</configuration>
Loading…
Cancel
Save