Client/Client.cs
author StephaneLenclud
Thu, 24 Sep 2015 14:35:50 +0200
changeset 158 e22bf44c4300
parent 123 0df386e37e29
permissions -rw-r--r--
Fixing issues where layout change would not be detected beccause of partial
field similarity between new and older layout.
Therefore we now clear our fields whenever our layout is changed.
Now resetting our create bitmap flag, hoping it will fix our rather large memory
usage when minimized.
     1 //
     2 // Copyright (C) 2014-2015 Stéphane Lenclud.
     3 //
     4 // This file is part of SharpDisplayManager.
     5 //
     6 // SharpDisplayManager is free software: you can redistribute it and/or modify
     7 // it under the terms of the GNU General Public License as published by
     8 // the Free Software Foundation, either version 3 of the License, or
     9 // (at your option) any later version.
    10 //
    11 // SharpDisplayManager is distributed in the hope that it will be useful,
    12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14 // GNU General Public License for more details.
    15 //
    16 // You should have received a copy of the GNU General Public License
    17 // along with SharpDisplayManager.  If not, see <http://www.gnu.org/licenses/>.
    18 //
    19 
    20 using System;
    21 using System.Collections.Generic;
    22 using System.Linq;
    23 using System.Text;
    24 using System.Threading.Tasks;
    25 using System.Windows.Forms;
    26 using SharpDisplay;
    27 using System.ServiceModel;
    28 using System.ServiceModel.Channels;
    29 
    30 
    31 namespace SharpDisplayClient
    32 {
    33     /// <summary>
    34     /// Client side Sharp Display callback implementation.
    35     /// </summary>
    36     [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
    37     public class Callback : ICallback, IDisposable
    38     {
    39         private MainForm MainForm { get; set; }
    40 
    41         public Callback(MainForm aMainForm)
    42         {
    43             MainForm = aMainForm;
    44         }
    45 
    46         /// <summary>
    47         /// Not used I believe.
    48         /// </summary>
    49         public void OnConnected()
    50         {
    51             //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread);
    52             //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId);
    53 
    54             MessageBox.Show("OnConnected()", "Client");
    55         }
    56 
    57 
    58         public void OnCloseOrder()
    59         {
    60             //Debug.Assert(Thread.CurrentThread.IsThreadPoolThread);
    61             //Trace.WriteLine("Callback thread = " + Thread.CurrentThread.ManagedThreadId);
    62 
    63             //MessageBox.Show("OnServerClosing()", "Client");
    64             MainForm.CloseConnectionThreadSafe();
    65             MainForm.CloseThreadSafe();
    66         }
    67 
    68         //From IDisposable
    69         public void Dispose()
    70         {
    71 
    72         }
    73     }
    74 
    75 
    76     /// <summary>
    77     /// Client side implementation of our Sharp Display Service.
    78     /// </summary>
    79     [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
    80     public class Client : DuplexClientBase<IService>
    81     {
    82         public string SessionId { get { return InnerChannel.SessionId; } }
    83 
    84         public Client(ICallback aCallback)
    85             : base(new InstanceContext(aCallback), new NetTcpBinding(SecurityMode.None, true), new EndpointAddress("net.tcp://localhost:8001/DisplayService"))
    86         { }
    87 
    88         public void SetName(string aClientName)
    89         {
    90             Channel.SetName(aClientName);
    91         }
    92 
    93         public void SetLayout(TableLayout aLayout)
    94         {
    95             Channel.SetLayout(aLayout);
    96         }
    97 
    98         public void SetField(DataField aField)
    99         {
   100             Channel.SetField(aField);
   101         }
   102 
   103         public void SetFields(System.Collections.Generic.IList<DataField> aFields)
   104         {
   105             Channel.SetFields(aFields);
   106         }
   107 
   108         public int ClientCount()
   109         {
   110             return Channel.ClientCount();
   111         }
   112 
   113         public bool IsReady()
   114         {
   115             return State == CommunicationState.Opened || State == CommunicationState.Created;
   116         }
   117     }
   118 
   119 
   120     /// <summary>
   121     /// Handle connection with our Sharp Display Server.
   122     /// If the connection is faulted it will attempt to restart it.
   123     /// </summary>
   124     public class DisplayClient
   125     {
   126         private Client iClient;
   127         private Callback iCallback;
   128         private bool resetingConnection = false;
   129 
   130         private MainForm MainForm { get; set; }
   131         public string SessionId { get { return iClient.SessionId; } }
   132         public string Name { get; private set; }
   133         private TableLayout Layout { get; set; }
   134         private System.Collections.Generic.IList<DataField> Fields { get; set; }
   135 
   136 
   137         public DisplayClient(MainForm aMainForm)
   138         {
   139             MainForm = aMainForm;
   140             Name = "";
   141             Fields = new DataField[]{};
   142         }
   143 
   144         /// <summary>
   145         /// Initialize our server connection.
   146         /// </summary>
   147         public void Open()
   148         {
   149             iCallback = new Callback(MainForm);
   150             iClient = new Client(iCallback);
   151         }
   152 
   153         /// <summary>
   154         /// Terminate our server connection.
   155         /// </summary>
   156         public void Close()
   157         {
   158             iClient.Close();
   159             iClient = null;
   160             iCallback.Dispose();
   161             iCallback = null;
   162         }
   163 
   164         /// <summary>
   165         /// Tells whether a server connection is available.
   166         /// </summary>
   167         /// <returns>True if a server connection is available. False otherwise.</returns>
   168         public bool IsReady()
   169         {
   170             return (iClient != null && iCallback != null && iClient.IsReady());
   171         }
   172 
   173         /// <summary>
   174         /// Check if our server connection is available and attempt reset it if it isn't.
   175         /// This is notably dealing with timed out connections.
   176         /// </summary>
   177         public void CheckConnection()
   178         {
   179             if (!IsReady() && !resetingConnection)
   180             {
   181                 //Try to reconnect
   182                 Open();
   183 
   184                 //Avoid stack overflow in case of persisting failure
   185                 resetingConnection = true;
   186 
   187                 try
   188                 {
   189                     //On reconnect there is a bunch of properties we need to reset
   190                     if (Name != "")
   191                     {
   192                         iClient.SetName(Name);
   193                     }
   194 
   195                     SetLayout(Layout);
   196                     iClient.SetFields(Fields);
   197                 }
   198                 finally
   199                 {
   200                     //Make sure our this state does not get out of sync
   201                     resetingConnection = true;
   202                 }
   203             }
   204         }
   205 
   206         /// <summary>
   207         /// Set our client's name.
   208         /// Client's name is typically user friendly.
   209         /// It does not have to be unique.
   210         /// </summary>
   211         /// <param name="aClientName">Our client name.</param>
   212         public void SetName(string aClientName)
   213         {
   214             Name = aClientName;
   215             CheckConnection();
   216             iClient.SetName(aClientName);
   217         }
   218 
   219         /// <summary>
   220         /// Set your client fields' layout.
   221         /// </summary>
   222         /// <param name="aLayout">The layout to apply for this client.</param>
   223         public void SetLayout(TableLayout aLayout)
   224         {
   225             Layout = aLayout;
   226             CheckConnection();
   227             iClient.SetLayout(aLayout);
   228         }
   229 
   230         /// <summary>
   231         /// Set the specified field.
   232         /// </summary>
   233         /// <param name="aField"></param>
   234         /// <returns>True if the specified field was set client side. False means you need to redefine all your fields using CreateFields.</returns>
   235         public bool SetField(DataField aField)
   236         {
   237             int i = 0;
   238             bool fieldFound = false;
   239             foreach (DataField field in Fields)
   240             {
   241                 if (field.Index == aField.Index)
   242                 {
   243                     //Update our field then
   244                     Fields[i] = aField;
   245                     fieldFound = true;
   246                     break;
   247                 }
   248                 i++;
   249             }
   250 
   251             if (!fieldFound)
   252             {
   253                 //Field not found, make sure to use CreateFields first after setting your layout.
   254                 return false;
   255             }
   256 
   257             CheckConnection();
   258             iClient.SetField(aField);
   259             return true;
   260         }
   261 
   262         /// <summary>
   263         /// Use this function when updating existing fields.
   264         /// </summary>
   265         /// <param name="aFields"></param>
   266         public bool SetFields(System.Collections.Generic.IList<DataField> aFields)
   267         {
   268             int fieldFoundCount = 0;
   269             foreach (DataField fieldUpdate in aFields)
   270             {
   271                 int i = 0;
   272                 foreach (DataField existingField in Fields)
   273                 {
   274                     if (existingField.Index == fieldUpdate.Index)
   275                     {
   276                         //Update our field then
   277                         Fields[i] = fieldUpdate;
   278                         fieldFoundCount++;
   279                         //Move on to the next field
   280                         break;
   281                     }
   282                     i++;
   283                 }
   284             }
   285 
   286             //
   287             if (fieldFoundCount!=aFields.Count)
   288             {
   289                 //Field not found, make sure to use CreateFields first after setting your layout.
   290                 return false;
   291             }
   292 
   293             CheckConnection();
   294             iClient.SetFields(aFields);
   295             return true;
   296         }
   297 
   298         /// <summary>
   299         /// Use this function when creating your fields.
   300         /// This must be done at least once after setting your layout.
   301         /// </summary>
   302         /// <param name="aFields"></param>
   303         public void CreateFields(System.Collections.Generic.IList<DataField> aFields)
   304         {
   305             Fields = aFields;
   306             CheckConnection();
   307             iClient.SetFields(aFields);
   308         }
   309 
   310         /// <summary>
   311         /// Provide the number of clients currently connected to our server.
   312         /// </summary>
   313         /// <returns>Number of clients currently connected to our server.</returns>
   314         public int ClientCount()
   315         {
   316             CheckConnection();
   317             return iClient.ClientCount();
   318         }
   319 
   320 
   321 
   322     }
   323 
   324 
   325 }