using BellwetherBackend.Utility;
using SocketTransfer;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Windows.Threading;
using ICSharpCode.SharpZipLib.Zip;
using System.Threading;
using System.Net;
namespace BellwetherBackend.SubPage
{
public enum UpdateState
{
TransferCompleted, Transferring, Disconnected, UpdateCompleted, UpdateFail, Abort, Connected
}
///
/// Interaction logic for UpdatePage.xaml
///
public partial class UpdatePage : UserControl
{
private static SolidColorBrush IsConnectBrush = new SolidColorBrush(Colors.Green);
private static SolidColorBrush IsDisconnectBrush = new SolidColorBrush(Colors.Red);
private static string rootPath = System.AppDomain.CurrentDomain.BaseDirectory;
private static string tempFolder = @"Temp\";
private static string defaultZipFileName = @"Temp\Data.zip";
private string ipAddress;
public string IpAddress
{
get
{
if (CheckIpFormat(uxIp1Text.Text) && CheckIpFormat(uxIp2Text.Text) && CheckIpFormat(uxIp3Text.Text) && CheckIpFormat(uxIp4Text.Text))
{
ipAddress = String.Format("{0}.{1}.{2}.{3}", uxIp1Text.Text, uxIp2Text.Text, uxIp3Text.Text, uxIp4Text.Text);
}
else
{
ipAddress = "error format";
}
return ipAddress;
}
set
{
ipAddress = value;
string[] str = ipAddress.Split('.');
if (str.Length > 3)
{
for (int i = 0; i < ipTextBlock.Length; i++)
{
ipTextBlock[i].Text = str[i];
}
}
this.Dispatcher.BeginInvoke((Action)delegate ()
{
CheckKioskConnect();
});
}
}
private int ipPort;
public int IpPort
{
set { ipPort = value; }
get { return ipPort; }
}
private bool isConnect;
public bool IsConnect
{
get { return isConnect; }
set
{
isConnect = value;
if (isConnect)
{
uxConnectStateRect.Fill = IsConnectBrush;
uxConnectBtn.IsEnabled = false;
uxDisConnectBtn.IsEnabled = true;
uxIpGrid.IsEnabled = false;
uxUpdateBtn.IsEnabled = true;
UpdatingState = UpdateState.Connected;
}
else
{
uxConnectStateRect.Fill = IsDisconnectBrush;
uxConnectBtn.IsEnabled = true;
uxDisConnectBtn.IsEnabled = false;
uxIpGrid.IsEnabled = true;
uxUpdateBtn.IsEnabled = false;
UpdatingState = UpdateState.Disconnected;
}
}
}
private UpdateState updatingState;
public UpdateState UpdatingState
{
get { return updatingState; }
set
{
updatingState = value;
}
}
private string localipAddress;
private TextBox[] ipTextBlock;
private BackgroundWorker connectWorker;
private SocketClient KioskSocketClient;
private bool canTransFileTag = false;
private List wholeDataFolder = new List();
private List cutFilePaths = new List();
public UpdatePage()
{
InitializeComponent();
CreateTempFolder();
new GlobalFunction();
uxConnectBtn.IconData = GlobalFunction.ConnectBtnData;
uxDisConnectBtn.IconData = GlobalFunction.DisconnectBtnData;
uxUpdateBtn.IconData = GlobalFunction.UpdateBtnData;
localipAddress = GetLocalIpAddress();
// 連線
ipTextBlock = new TextBox[]
{
uxIp1Text, uxIp2Text, uxIp3Text, uxIp4Text
};
IpAddress = Properties.Settings.Default["ConnectIP"].ToString();
IpPort = int.Parse(Properties.Settings.Default["ConnectPort"].ToString());
connectWorker = new BackgroundWorker();
connectWorker.WorkerSupportsCancellation = true;
connectWorker.DoWork += connectWorker_DoWork;
connectWorker.RunWorkerCompleted += connectWorker_RunWorkerCompleted;
uxIp1Text.TextChanged += uxIp1Text_TextChanged;
uxIp2Text.TextChanged += uxIp1Text_TextChanged;
uxIp3Text.TextChanged += uxIp1Text_TextChanged;
uxIp4Text.TextChanged += uxIp1Text_TextChanged;
this.Loaded += UpdatePage_Loaded;
}
private void UpdatePage_Loaded(object sender, RoutedEventArgs e)
{
//Setting.PageNameList[x]
List checkBoxList = new List();
foreach (UIElement element in uxUpdateListPanel.Children)
{
if (element is CheckBox checkBox)
checkBoxList.Add(checkBox);
}
//var visualElementCnt = checkBoxList.Count;
//var dataStringCnt = Setting.PageNameList.Count;
//for (int pageIndex = 0; pageIndex + 1 < visualElementCnt && pageIndex < dataStringCnt; pageIndex++)
//{
// checkBoxList[pageIndex + 1].Content = Setting.PageNameList[pageIndex];
//}
}
public void CheckKioskConnect()
{
if (connectWorker.IsBusy)
{
connectWorker.CancelAsync();
}
connectWorker.RunWorkerAsync();
}
public void Disconnect()
{
DisconnectHandle();
}
private void StartLoading()
{
uxProgressBar.Visibility = Visibility.Visible;
uxWorkingGrid.IsEnabled = false;
uxWorkingGrid.Opacity = 0.3;
}
private void StopLoading()
{
uxProgressBar.Visibility = Visibility.Collapsed;
uxWorkingGrid.IsEnabled = true;
uxWorkingGrid.Opacity = 1.0;
}
private void CreateTempFolder()
{
string path = System.IO.Path.Combine(rootPath, tempFolder);
if (Directory.Exists(path))
{
ClearTempFolder();
}
else
{
Directory.CreateDirectory(path);
}
}
private void ClearTempFolder()
{
string path = System.IO.Path.Combine(rootPath, tempFolder);
if (Directory.Exists(path))
{
string[] files = Directory.GetFiles(path);
foreach (string file in files)
{
try
{
if (File.Exists(file))
File.Delete(file);
}
catch { }
}
}
}
private string GetLocalIpAddress()
{
string result = "";
string strHostName = Dns.GetHostName();
IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);
foreach (IPAddress ipaddress in iphostentry.AddressList)
{
// 只取得IP V4的Address
if (ipaddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
{
result = ipaddress.ToString();
}
}
return result;
}
private bool CheckIpFormat(string str)
{
byte checkPart = 0;
if (!byte.TryParse(str, out checkPart))
{
return false;
}
return true;
}
private void InitialUpdateStatus()
{
this.Dispatcher.BeginInvoke((Action)delegate ()
{
uxStatus.Text = "";
uxUpdateProgressBar.Value = 0;
if (KioskSocketClient != null)
uxUpdateBtn.IsEnabled = true;
ClearTempFolder();
}, DispatcherPriority.Background);
}
private void ChangeUpdateProgrssBarValue(double value)
{
this.Dispatcher.BeginInvoke((Action)delegate ()
{
uxUpdateProgressBar.Value += value;
}, DispatcherPriority.Background);
}
private void uxIp1Text_TextChanged(object sender, TextChangedEventArgs e)
{
Properties.Settings.Default["ConnectIP"] = uxIp1Text.Text + "." + uxIp2Text.Text + "." + uxIp3Text.Text + "." + uxIp4Text.Text;
}
private void connectWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.Dispatcher.BeginInvoke((Action)delegate ()
{
StopLoading();
}, DispatcherPriority.Background);
}
private void connectWorker_DoWork(object sender, DoWorkEventArgs e)
{
this.Dispatcher.BeginInvoke((Action)delegate ()
{
// loading bar
StartLoading();
}, DispatcherPriority.Background);
if (KioskSocketClient != null)
{
KioskSocketClient.ServerReady -= KioskSocketClient_ServerReady;
KioskSocketClient.ServerClose -= KioskSocketClient_ServerClose;
}
string serverIp = String.Empty;
this.Dispatcher.Invoke((Action)delegate ()
{
serverIp = IpAddress;
if (serverIp != "error format")
{
KioskSocketClient = new SocketClient(IpAddress, IpPort, localipAddress);
KioskSocketClient.ServerReady += KioskSocketClient_ServerReady;
KioskSocketClient.ServerClose += KioskSocketClient_ServerClose;
}
}, DispatcherPriority.Background);
if (serverIp != "error format")
{
try
{
KioskSocketClient.Connect();
}
catch
{
this.Dispatcher.BeginInvoke((Action)delegate ()
{
IsConnect = false;
}, DispatcherPriority.Background);
}
}
else
{
this.Dispatcher.BeginInvoke((Action)delegate ()
{
IsConnect = false;
}, DispatcherPriority.Background);
}
}
private void KioskSocketClient_ServerReady(string serverIP, string version)
{
this.Dispatcher.BeginInvoke((Action)delegate ()
{
IsConnect = true;
}, DispatcherPriority.Background);
}
private void KioskSocketClient_ServerClose(string serverIP)
{
this.Dispatcher.BeginInvoke((Action)delegate ()
{
IsConnect = false;
}, DispatcherPriority.Background);
}
private void uxConnect_Click(object sender, RoutedEventArgs e)
{
CheckKioskConnect();
}
private void uxDisConnectBtn_Click(object sender, RoutedEventArgs e)
{
DisconnectHandle();
}
private void DisconnectHandle()
{
if (KioskSocketClient != null)
{
KioskSocketClient.ServerReady -= KioskSocketClient_ServerReady;
KioskSocketClient.ServerClose -= KioskSocketClient_ServerClose;
KioskSocketClient.Close();
KioskSocketClient = null;
}
IsConnect = false;
UpdatingState = UpdateState.Abort;
}
#region 更新開始
private void uxUpdateBtn_Click(object sender, RoutedEventArgs e)
{
List packageFilePath = new List();
canTransFileTag = true;
uxUpdateBtn.IsEnabled = false;
// 收集欲打包的資料路徑
StatusChange("收集打包資訊..");
wholeDataFolder = GetPackageFolder();
packageFilePath = GetUpdatePackageFilePath();
if (wholeDataFolder.Count == 0)
{
StatusChange("沒有選擇任何傳送檔案..");
// 所有狀態回復
WpfDelayDoWork.DoBackgroundWork(InitialUpdateStatus, 3000);
return;
}
// Step 1 : 打包
uxUpdateProgressBar.Value = 0;
StatusChange("開始打包..");
BackgroundWorker zipWorker = new BackgroundWorker();
zipWorker.WorkerSupportsCancellation = true;
zipWorker.DoWork += zipWorker_DoWork;
zipWorker.RunWorkerCompleted += zipWorker_RunWorkerCompleted;
zipWorker.RunWorkerAsync(packageFilePath);
}
private void StatusChange(string status)
{
this.Dispatcher.BeginInvoke((Action)delegate ()
{
uxStatus.Text = status;
}, DispatcherPriority.Background);
}
private void DivisionZipFile()
{
// Step 2 : 分割
uxUpdateProgressBar.Value = 0;
StatusChange("分割封裝檔..");
BackgroundWorker divisionWorker = new BackgroundWorker();
divisionWorker.WorkerSupportsCancellation = true;
divisionWorker.DoWork += divisionWorker_DoWork;
divisionWorker.RunWorkerCompleted += divisionWorker_RunWorkerCompleted;
divisionWorker.RunWorkerAsync();
}
private void TransCutFile()
{
// Step 3 : 傳送
uxUpdateProgressBar.Value = 0;
StatusChange("檔案傳送中...");
BackgroundWorker updateWorker = new BackgroundWorker();
updateWorker.WorkerSupportsCancellation = true;
updateWorker.DoWork += updateWorker_DoWork;
updateWorker.RunWorkerCompleted += updateWorker_RunWorkerCompleted;
updateWorker.RunWorkerAsync();
}
#endregion
#region 收集欲打包的資料
private List GetPackageFolder()
{
List resultPaceage = new List();
for (int i = 0; i < uxUpdateListPanel.Children.Count; i++)
{
CheckBox chkBtn = uxUpdateListPanel.Children[i] as CheckBox;
if (chkBtn != null)
{
if (chkBtn.IsChecked == true)
{
if (chkBtn.Tag.ToString() != "")
resultPaceage.Add(chkBtn.Tag.ToString());
}
}
}
return resultPaceage;
}
private List GetUpdatePackageFilePath()
{
List resultPackage = new List();
// 整理要打包的東西 : 所有要打包的檔案的相對根目錄底下路徑
for (int i = 0; i < wholeDataFolder.Count; i++)
{
switch (wholeDataFolder[i])
{
case "Basic":
PackageBasicSetting(resultPackage);
break;
case "FrontPage":
PackageFrontPageSetting(resultPackage);
break;
case "History":
PackageHistoryWall(resultPackage, Setting.PageType.History);
break;
case "Product":
PackageHistoryWall(resultPackage, Setting.PageType.Product);
break;
case "CSR":
PackageHistoryWall(resultPackage, Setting.PageType.CSR);
break;
}
}
return resultPackage;
}
private void PackageBasicSetting(List resultPackage)
{
resultPackage.Add(Setting.settingJsonDataPath);
}
private void PackageFrontPageSetting(List resultPackage)
{
string[] files = Directory.GetFiles(Setting.frontPageDirectory);
resultPackage.AddRange(files);
}
private void PackageHistoryWall(List resultPackage, Setting.PageType type)
{
string folderPath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "Data", Setting.PageFolderName[type]);
string DataConfigFileName = System.IO.Path.Combine(folderPath, @"Setting\ConfigSetting.ini");
string historyFileName = System.IO.Path.Combine(folderPath, @"HistoryWallData\HistoryFile.ini");
string DataThumFileFolder = System.IO.Path.Combine(folderPath, @"Thumb\");
string DataJsonImgFileFolder = System.IO.Path.Combine(folderPath, @"HistoryImage\");
// History : 1. Setting\ConfigSetting.ini + 2. HistoryWallData\HistoryFile.ini + 3. Thumb\bgMap file and logoMap file + 4. HistoryImage 整包
if (File.Exists(DataConfigFileName))
{
resultPackage.Add(DataConfigFileName);
}
if (File.Exists(historyFileName))
{
resultPackage.Add(historyFileName);
}
string[] files = Directory.GetFiles(DataThumFileFolder);
foreach (string file in files)
{
// 只接受 bgMap 及 logoMap 兩個檔名檔案
if (GlobalFunction.CheckFileIsImage(file) && (file.IndexOf("bgMap") != -1 || file.IndexOf("logoMap") != -1))
{
resultPackage.Add(file);
}
}
if (Directory.Exists(DataJsonImgFileFolder))
{
List dirs = new List(Directory.EnumerateDirectories(DataJsonImgFileFolder));
foreach (var dir in dirs)
{
string[] inforfiles = Directory.GetFiles(dir);
foreach (string file in inforfiles)
{
// 接受圖片或影片
if (GlobalFunction.CheckFileIsImage(file) || GlobalFunction.CheckFileIsVideo(file))
{
resultPackage.Add(file);
}
}
}
}
}
#endregion
#region 打包
private void zipWorker_DoWork(object sender, DoWorkEventArgs e)
{
List packagePathList = e.Argument as List;
FileStream FS = File.Create(defaultZipFileName);
ZipOutputStream s = new ZipOutputStream(FS);
string currentPath = Directory.GetCurrentDirectory();
s.SetLevel(9); //0 ~ 9
double stepValue = 100 / packagePathList.Count;
for (int i = 0; i < packagePathList.Count; i++)
{
FileStream fs = File.OpenRead(packagePathList[i]);
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
string zipPath = packagePathList[i];
if (packagePathList[i].Contains(currentPath))
zipPath = zipPath.Remove(0, currentPath.Length + 1);
ZipEntry entry = new ZipEntry(zipPath);
entry.DateTime = DateTime.Now;
entry.Size = fs.Length;
fs.Close();
s.PutNextEntry(entry);
s.Write(buffer, 0, buffer.Length);
ChangeUpdateProgrssBarValue(stepValue);
}
s.Dispose();
s.Close();
}
private void zipWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
StatusChange("打包完成..");
uxUpdateProgressBar.Value = 100;
//切割打包資料夾
WpfDelayDoWork.DoBackgroundWork(DivisionZipFile, 1000);
}
#endregion
#region 切割
private void divisionWorker_DoWork(object sender, DoWorkEventArgs e)
{
string zipFilePath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), defaultZipFileName);
if (File.Exists(zipFilePath))
{
try
{
int segmentSize = 4194304; //4MB
long fileSize = new FileInfo(zipFilePath).Length;
int datas = 0;
int segmentCount = (int)(fileSize / (long)segmentSize);
int lastSegmentSize = (int)(fileSize % (long)segmentSize);
segmentCount = lastSegmentSize > 0 ? segmentCount + 1 : segmentCount;
double stepValue = 100 / segmentCount;
FileStream fs = File.OpenRead(zipFilePath);
cutFilePaths = new List();
for (int i = 0; i < segmentCount; i++)
{
byte[] binaryData;
string segmentFileName = zipFilePath.Replace(".zip", String.Empty) + "[" + (i + 1) + "].cut";
FileStream fOut = File.OpenWrite(segmentFileName);
if (lastSegmentSize > 0 && i == segmentCount - 1)
{
binaryData = new byte[lastSegmentSize];
datas = fs.Read(binaryData, 0, lastSegmentSize);
fOut.Write(binaryData, 0, lastSegmentSize);
}
else
{
binaryData = new byte[segmentSize];
datas = fs.Read(binaryData, 0, segmentSize);
fOut.Write(binaryData, 0, segmentSize);
}
fOut.Flush();
fOut.Close();
ChangeUpdateProgrssBarValue(stepValue);
cutFilePaths.Add(segmentFileName);
}
fs.Close();
File.Delete(zipFilePath);
canTransFileTag = true;
}
catch
{
canTransFileTag = false;
}
}
else
{
canTransFileTag = false;
}
}
private void divisionWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
StatusChange("分割完成..");
uxUpdateProgressBar.Value = 100;
if (canTransFileTag)
{
//傳輸更新檔案開始
WpfDelayDoWork.DoBackgroundWork(TransCutFile, 1000);
return;
}
StatusChange("分割失敗..");
// 所有狀態回復
WpfDelayDoWork.DoBackgroundWork(InitialUpdateStatus, 3000);
}
#endregion
#region 傳送
bool isSendComplete = false;
private void updateWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (cutFilePaths.Count > 0)
{
try
{
isSendComplete = false;
// 通知分割檔案總數
KioskSocketClient.NotifyFileTransferStart(cutFilePaths.Count);
// 掛上前台更新狀況事件
KioskSocketClient.SendSegmentFileFinish += KioskSocketClient_SendSegmentFileFinish;
KioskSocketClient.FailSendFile += KioskSocketClient_FailSendFile;
KioskSocketClient.ReceiveServerNotify += KioskSocketClient_ReceiveServerNotify;
//傳送 Cut File
for (int i = 0; i < cutFilePaths.Count; i++)
{
while (isSendComplete)
{
Thread.Sleep(1000);
}
KioskSocketClient.SendFile(cutFilePaths[i], "0");
isSendComplete = true;
}
}
catch
{
KioskSocketClient = null;
canTransFileTag = false;
}
}
}
private void updateWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (canTransFileTag)
{
//傳輸更新檔案開始
StatusChange("傳送完成..");
uxUpdateProgressBar.Value = 100;
return;
}
StatusChange("傳送失敗..");
// 所有狀態回復
WpfDelayDoWork.DoBackgroundWork(InitialUpdateStatus, 3000);
}
private void KioskSocketClient_SendSegmentFileFinish(string serverIP, string index)
{
double stepValue = 100 / cutFilePaths.Count;
ChangeUpdateProgrssBarValue(stepValue);
isSendComplete = false;
}
#endregion
#region 前台更新狀況回報
private void KioskSocketClient_FailSendFile(object sender, EventArgs e)
{
StatusChange("傳輸異常...");
// 所有狀態回復
WpfDelayDoWork.DoBackgroundWorkAsync(Dispatcher.CurrentDispatcher, InitialUpdateStatus, 3000);
}
private void KioskSocketClient_ReceiveServerNotify(string serverIP, string message)
{
if (message.Equals("Success"))
{
StatusChange("前台更新完成重新啟動中...");
// 所有狀態回復
WpfDelayDoWork.DoBackgroundWorkAsync(Dispatcher.CurrentDispatcher, InitialUpdateStatus, 3000);
}
else if (message.Equals("Fail"))
{
StatusChange("傳輸異常...");
// 所有狀態回復
WpfDelayDoWork.DoBackgroundWorkAsync(Dispatcher.CurrentDispatcher, InitialUpdateStatus, 3000);
}
}
#endregion
}
public class WpfDelayDoWork
{
public static void DoWork(Action action, int millisecond = 300)
{
new Action(DoWorkAsync).BeginInvoke(Dispatcher.CurrentDispatcher, action, millisecond, null, null);
}
public static void DoBackgroundWork(Action action, int millisecond = 300)
{
new Action(DoBackgroundWorkAsync).BeginInvoke(Dispatcher.CurrentDispatcher, action, millisecond, null, null);
}
public static void DoWorkAsync(Dispatcher dispatcher, Action action, int millisecond)
{
System.Threading.Thread.Sleep(millisecond);
dispatcher.BeginInvoke(action);
}
public static void DoBackgroundWorkAsync(Dispatcher dispatcher, Action action, int millisecond)
{
System.Threading.Thread.Sleep(millisecond);
dispatcher.Invoke(action, DispatcherPriority.Background);
}
}
}