diff --git a/Interact/Client.cs b/Interact/Client.cs new file mode 100644 index 0000000..5b324cf --- /dev/null +++ b/Interact/Client.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net.Sockets; +using System.Net; +using System.Threading; +using System.Collections.Concurrent; +using Newtonsoft.Json.Linq; + +namespace Interact +{ + //连接中断 + public delegate void DisconnectHandler(Exception ex); + //登录反馈到达 + public delegate void LoginDoneHandler(JObject head, User user); + + public static partial class StormClient + { + //连接中断事件 + public static event DisconnectHandler OnDisconnect; + //登录结果处理事件 + public static event LoginDoneHandler OnLoginDone; + + //TCP客户端 + private static TcpClient tcpClient; + //消息发送队列 + private static BlockingCollection sendQueue; + //数据读取线程 + private static Thread readLoopThread; + //数据发送线程 + private static Thread sendLoopThread; + + static StormClient() + { + tcpClient = new TcpClient(); + sendQueue = new BlockingCollection(); + } + /// + /// 初始化客户端,连接服务器。如果成功则启动数据接收和发送线程 + /// + /// 如果已连接到服务器返回true,否则返回false。 + public static bool Initialize() + { + if (StormClient.tcpClient.Connected) + return true; + StormClient.tcpClient.Connect(Interact.Properties.Resources.RemoteServerAddr, int.Parse(Interact.Properties.Resources.RemoteServerPort)); + if (!StormClient.tcpClient.Connected) + return false; + if (sendLoopThread != null) + sendLoopThread.Abort(); + if (readLoopThread != null) + readLoopThread.Abort(); + //启动数据收发线程 + sendLoopThread = new Thread(new ThreadStart(SendLoop)); + readLoopThread = new Thread(new ThreadStart(ReadLoop)); + //设置为后台线程 + sendLoopThread.IsBackground = readLoopThread.IsBackground = true; + sendLoopThread.Start(); + readLoopThread.Start(); + return true; + } + + /// + /// 登录。此操作为异步操作,完成后产生OnLoginDone事件。 + /// + /// 成功将请求加入发送队列返回true,否则返回false。 + /// 用户名 + /// 密码 + /// 数据发送完成回调函数。注意,结果处理回调请设置OnLoginDone事件 + public static bool RequestLogin(string user, string password, Action callback = null) + { + JsonLogInfoHead logInfo = new JsonLogInfoHead() + { + Token = "", + Operation = Operations.Login.ToString(), + User = user, + Pwd = password + }; + Packet packet = new Packet + { + Head = logInfo, + Data = null, + CallBack = callback + }; + return Send(packet); + } + + } +} diff --git a/Interact/Handle.cs b/Interact/Handle.cs new file mode 100644 index 0000000..1bb74c6 --- /dev/null +++ b/Interact/Handle.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +namespace Interact +{ + //对数据的处理相关内容 + public partial class StormClient + { + //根据包头信息处理数据 + private static void HandleAll(byte[] headData, byte[] data) + { + string head = Encoding.UTF8.GetString(headData); + JObject jsonObj = (JObject)JsonConvert.DeserializeObject(head); + switch ((Operations)Enum.Parse(typeof(Operations), jsonObj[Strings.Operation].ToString())) + { + case Operations.Login: + HandleLoginResult(jsonObj, data); + break; + case Operations.Panic: + case Operations.TransMessage: + case Operations.SendMessage: + case Operations.Ping: + case Operations.Logout: + case Operations.Offline: + case Operations.GetUserList: + case Operations.UpdateUserInfo: + case Operations.GetUserPhoto: + default: + break; + } + } + //处理登录反馈消息 + private static void HandleLoginResult(JObject head, byte[] data) + { + User user = null; + if (head[Strings.Error].ToString() == "") + user = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(data)) as User; + OnLoginDone?.Invoke(head, user); + } + } + +} diff --git a/Interact/Interact.csproj b/Interact/Interact.csproj new file mode 100644 index 0000000..7582ed8 --- /dev/null +++ b/Interact/Interact.csproj @@ -0,0 +1,68 @@ + + + + + Debug + AnyCPU + {CEF054AF-95B7-4B88-934E-02705FEEA554} + Library + Properties + Interact + Interact + v4.0 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + .\Newtonsoft.Json.dll + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + \ No newline at end of file diff --git a/Interact/JsonObject.cs b/Interact/JsonObject.cs new file mode 100644 index 0000000..8498d7e --- /dev/null +++ b/Interact/JsonObject.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +//此文件定义Json序列化与反序列化时使用的数据结构,仅内部使用 + +namespace Interact +{ + //登录信息包头 + internal class JsonLogInfoHead : BaseHead + { + public string User; + public string Pwd; + } + +} diff --git a/Interact/Message.cs b/Interact/Message.cs new file mode 100644 index 0000000..664320f --- /dev/null +++ b/Interact/Message.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Interact +{ + //定义一则用户消息 + public class Message + { + public static UInt32 MaxHeadLength; //最大包头长度 + public static UInt32 MaxMessageLength; //最大消息长度 + + public DateTime When { get; } //服务器接收时间 + public User From; //发送者 + public string Content; //消息内容 + } + + //包头基本结构 + public class BaseHead + { + //请求ID,由发送方定义的随机字符串。如果接受方有返回数据应包含相同的Token + public string Token; + //操作类型,决定数据的其他内容 + public string Operation; + } + // 接受方返回的执行结果反馈包头,包含错误文本 + public class ResultHead : BaseHead + { + //错误文本,为空则执行成功 + public string Error; + } + + //从服务器接收的原始数据封包 + internal class Packet + { + public BaseHead Head; //包头 + public byte[] Data; //包内容 + public Action CallBack; //数据发送完成的回调函数。注意,此时仅保证数据已发送, + //服务器可能并没有处理完成请求 + } + //允许请求的操作列表。具体定义见设计文档 + public enum Operations + { + Panic, + TransMessage, + SendMessage, + Ping, + Login, + Logout, + Offline, + GetUserList, + UpdateUserInfo, + GetUserPhoto + } +} diff --git a/Interact/Properties/AssemblyInfo.cs b/Interact/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..49a4d20 --- /dev/null +++ b/Interact/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Interact")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Interact")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("cef054af-95b7-4b88-934e-02705feea554")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Interact/Properties/Resources.Designer.cs b/Interact/Properties/Resources.Designer.cs new file mode 100644 index 0000000..b1a5aa2 --- /dev/null +++ b/Interact/Properties/Resources.Designer.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Interact.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Interact.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to localhost. + /// + internal static string RemoteServerAddr { + get { + return ResourceManager.GetString("RemoteServerAddr", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 3727. + /// + internal static string RemoteServerPort { + get { + return ResourceManager.GetString("RemoteServerPort", resourceCulture); + } + } + } +} diff --git a/Interact/Properties/Resources.resx b/Interact/Properties/Resources.resx new file mode 100644 index 0000000..3029213 --- /dev/null +++ b/Interact/Properties/Resources.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + localhost + + + 3727 + + \ No newline at end of file diff --git a/Interact/Read.cs b/Interact/Read.cs new file mode 100644 index 0000000..019416e --- /dev/null +++ b/Interact/Read.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net; +using System.Net.Sockets; + +namespace Interact +{ + //读取数据相关内容 + public partial class StormClient + { + // 数据读取线程,从tcp连接读取数据 + private static void ReadLoop() + { + NetworkStream stream = StormClient.tcpClient.GetStream(); + try + { + while (tcpClient.Connected) + { + byte[] head = ReadDataWithLength(stream); + byte[] data = ReadDataWithLength(stream); + HandleAll(head, data); + } + } + catch (System.IO.IOException ex) + { + tcpClient.Close(); + OnDisconnect(ex); + } + catch (ObjectDisposedException ex) + { + tcpClient.Close(); + OnDisconnect(ex); + } + } + // 从网络流读取数据 + private static byte[] ReadDataWithLength(NetworkStream stream) + { + byte[] lenBuffer = new byte[4]; //数据长度 + //获取数据长度 + stream.Read(lenBuffer, 0, 4); + int length = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(lenBuffer, 0)); + if (length <= 0) + return null; + //读取数据 + byte[] data = new byte[length]; + stream.Read(data, 0, length); + return data; + } + } +} diff --git a/Interact/Send.cs b/Interact/Send.cs new file mode 100644 index 0000000..7515499 --- /dev/null +++ b/Interact/Send.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json; +using System.Net; +using System.Net.Sockets; + +namespace Interact +{ + //发送数据相关内容 + public partial class StormClient + { + // 消息写入线程,向tcp连接写入数据 + private static void SendLoop() + { + NetworkStream stream = tcpClient.GetStream(); + try + { + foreach (Packet packet in sendQueue.GetConsumingEnumerable()) + { + //结束循环 + if (!tcpClient.Connected) + break; + //向tcp连接写数据 + byte[] lenBuffer; //数据长度缓存 + byte[] headData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(packet.Head)); + //写包头 + lenBuffer = BitConverter.GetBytes((UInt32)IPAddress.HostToNetworkOrder(headData.Length)); + stream.Write(lenBuffer, 0, 4); + stream.Write(headData, 0, headData.Length); + //写数据 + int length = 0; + if (packet.Data != null) + length = packet.Data.Length; + lenBuffer = BitConverter.GetBytes((UInt32)IPAddress.HostToNetworkOrder(length)); + stream.Write(lenBuffer, 0, 4); + if (length > 0) + stream.Write(packet.Data, 0, packet.Data.Length); + //发送完成回调 + packet.CallBack?.Invoke(packet.Head); + } + } + catch (System.IO.IOException ex) + { + tcpClient.Close(); + OnDisconnect?.Invoke(ex); + } + catch (ObjectDisposedException ex) + { + tcpClient.Close(); + OnDisconnect?.Invoke(ex); + } + } + //发送数据 + private static bool Send(Packet packet) + { + if (sendLoopThread == null || !sendLoopThread.IsAlive) + return false; + //加入数据发送队列等待 + sendQueue.Add(packet); + return true; + } + } +} diff --git a/Interact/Strings.cs b/Interact/Strings.cs new file mode 100644 index 0000000..508a169 --- /dev/null +++ b/Interact/Strings.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Interact +{ + //字符串常量 + public static class Strings + { + public const string Token = "Token"; + public const string Operation = "Operation"; + public const string Error = "Error"; + } +} diff --git a/Interact/User.cs b/Interact/User.cs new file mode 100644 index 0000000..f8ad5db --- /dev/null +++ b/Interact/User.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Interact +{ + //用户 + public class User + { + public static User Me; //当前用户 + + public string Name; //用户名 + public string NickName; //昵称 + public string Motto; //个性签名 + public UserGroup Group; //用户组 + } + + //用户类型 + public enum UserGroup + { + User, //普通用户 + Vip, //会员 + Admin, //管理员 + Group //群组 + } +} diff --git a/StormChat.sln b/StormChat.sln new file mode 100644 index 0000000..699c9eb --- /dev/null +++ b/StormChat.sln @@ -0,0 +1,51 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28010.2041 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StormChat", "StormChat\StormChat.csproj", "{01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interact", "Interact\Interact.csproj", "{CEF054AF-95B7-4B88-934E-02705FEEA554}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}.Debug|x64.ActiveCfg = Debug|Any CPU + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}.Debug|x64.Build.0 = Debug|Any CPU + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}.Debug|x86.ActiveCfg = Debug|Any CPU + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}.Debug|x86.Build.0 = Debug|Any CPU + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}.Release|Any CPU.Build.0 = Release|Any CPU + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}.Release|x64.ActiveCfg = Release|Any CPU + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}.Release|x64.Build.0 = Release|Any CPU + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}.Release|x86.ActiveCfg = Release|Any CPU + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD}.Release|x86.Build.0 = Release|Any CPU + {CEF054AF-95B7-4B88-934E-02705FEEA554}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CEF054AF-95B7-4B88-934E-02705FEEA554}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CEF054AF-95B7-4B88-934E-02705FEEA554}.Debug|x64.ActiveCfg = Debug|Any CPU + {CEF054AF-95B7-4B88-934E-02705FEEA554}.Debug|x64.Build.0 = Debug|Any CPU + {CEF054AF-95B7-4B88-934E-02705FEEA554}.Debug|x86.ActiveCfg = Debug|Any CPU + {CEF054AF-95B7-4B88-934E-02705FEEA554}.Debug|x86.Build.0 = Debug|Any CPU + {CEF054AF-95B7-4B88-934E-02705FEEA554}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CEF054AF-95B7-4B88-934E-02705FEEA554}.Release|Any CPU.Build.0 = Release|Any CPU + {CEF054AF-95B7-4B88-934E-02705FEEA554}.Release|x64.ActiveCfg = Release|Any CPU + {CEF054AF-95B7-4B88-934E-02705FEEA554}.Release|x64.Build.0 = Release|Any CPU + {CEF054AF-95B7-4B88-934E-02705FEEA554}.Release|x86.ActiveCfg = Release|Any CPU + {CEF054AF-95B7-4B88-934E-02705FEEA554}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {16287CCA-1001-41B2-B0BA-101618B1DCFB} + EndGlobalSection +EndGlobal diff --git a/StormChat/App.config b/StormChat/App.config new file mode 100644 index 0000000..74ade9d --- /dev/null +++ b/StormChat/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/StormChat/LogForm.Designer.cs b/StormChat/LogForm.Designer.cs new file mode 100644 index 0000000..14587c3 --- /dev/null +++ b/StormChat/LogForm.Designer.cs @@ -0,0 +1,160 @@ +namespace StormChat +{ + partial class LogForm + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows 窗体设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.txtUser = new System.Windows.Forms.TextBox(); + this.txtPassword = new System.Windows.Forms.TextBox(); + this.btnLogin = new System.Windows.Forms.Button(); + this.chkRemerberPassword = new System.Windows.Forms.CheckBox(); + this.chkAutoLogin = new System.Windows.Forms.CheckBox(); + this.picPhoto = new System.Windows.Forms.PictureBox(); + this.lblBadge = new System.Windows.Forms.Label(); + ((System.ComponentModel.ISupportInitialize)(this.picPhoto)).BeginInit(); + this.SuspendLayout(); + // + // txtUser + // + this.txtUser.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtUser.Font = new System.Drawing.Font("DengXian", 12.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtUser.Location = new System.Drawing.Point(207, 260); + this.txtUser.Margin = new System.Windows.Forms.Padding(4); + this.txtUser.Name = "txtUser"; + this.txtUser.Size = new System.Drawing.Size(351, 30); + this.txtUser.TabIndex = 1; + this.txtUser.Text = "mattuy"; + // + // txtPassword + // + this.txtPassword.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.txtPassword.Font = new System.Drawing.Font("DengXian", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtPassword.Location = new System.Drawing.Point(207, 295); + this.txtPassword.Margin = new System.Windows.Forms.Padding(133, 4, 4, 4); + this.txtPassword.Name = "txtPassword"; + this.txtPassword.PasswordChar = '*'; + this.txtPassword.Size = new System.Drawing.Size(351, 32); + this.txtPassword.TabIndex = 3; + this.txtPassword.Text = "1233211234567"; + // + // btnLogin + // + this.btnLogin.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + this.btnLogin.Font = new System.Drawing.Font("Microsoft YaHei", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnLogin.Location = new System.Drawing.Point(207, 362); + this.btnLogin.Margin = new System.Windows.Forms.Padding(4); + this.btnLogin.Name = "btnLogin"; + this.btnLogin.Size = new System.Drawing.Size(352, 48); + this.btnLogin.TabIndex = 6; + this.btnLogin.Text = "登录"; + this.btnLogin.UseVisualStyleBackColor = true; + this.btnLogin.Click += new System.EventHandler(this.btnLogin_Click); + // + // chkRemerberPassword + // + this.chkRemerberPassword.AutoSize = true; + this.chkRemerberPassword.Font = new System.Drawing.Font("SimSun", 10F); + this.chkRemerberPassword.Location = new System.Drawing.Point(208, 335); + this.chkRemerberPassword.Margin = new System.Windows.Forms.Padding(4); + this.chkRemerberPassword.Name = "chkRemerberPassword"; + this.chkRemerberPassword.Size = new System.Drawing.Size(98, 21); + this.chkRemerberPassword.TabIndex = 4; + this.chkRemerberPassword.Text = "记住密码"; + this.chkRemerberPassword.UseVisualStyleBackColor = true; + // + // chkAutoLogin + // + this.chkAutoLogin.AutoSize = true; + this.chkAutoLogin.Font = new System.Drawing.Font("SimSun", 10F); + this.chkAutoLogin.Location = new System.Drawing.Point(449, 335); + this.chkAutoLogin.Margin = new System.Windows.Forms.Padding(4); + this.chkAutoLogin.Name = "chkAutoLogin"; + this.chkAutoLogin.Size = new System.Drawing.Size(98, 21); + this.chkAutoLogin.TabIndex = 5; + this.chkAutoLogin.Text = "自动登录"; + this.chkAutoLogin.UseVisualStyleBackColor = true; + // + // picPhoto + // + this.picPhoto.Image = global::StormChat.Properties.Resources.DefaultPhoto; + this.picPhoto.Location = new System.Drawing.Point(21, 260); + this.picPhoto.Margin = new System.Windows.Forms.Padding(4); + this.picPhoto.Name = "picPhoto"; + this.picPhoto.Size = new System.Drawing.Size(160, 150); + this.picPhoto.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.picPhoto.TabIndex = 4; + this.picPhoto.TabStop = false; + // + // lblBadge + // + this.lblBadge.BackColor = System.Drawing.Color.Transparent; + this.lblBadge.Dock = System.Windows.Forms.DockStyle.Top; + this.lblBadge.Font = new System.Drawing.Font("Microsoft Sans Serif", 50.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(2))); + this.lblBadge.ForeColor = System.Drawing.Color.Maroon; + this.lblBadge.Image = global::StormChat.Properties.Resources.LogFormBackground; + this.lblBadge.Location = new System.Drawing.Point(0, 0); + this.lblBadge.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblBadge.Name = "lblBadge"; + this.lblBadge.Size = new System.Drawing.Size(579, 229); + this.lblBadge.TabIndex = 2; + this.lblBadge.Text = "StormChat"; + this.lblBadge.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + // + // LogForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(579, 428); + this.Controls.Add(this.chkAutoLogin); + this.Controls.Add(this.chkRemerberPassword); + this.Controls.Add(this.btnLogin); + this.Controls.Add(this.picPhoto); + this.Controls.Add(this.txtPassword); + this.Controls.Add(this.lblBadge); + this.Controls.Add(this.txtUser); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Margin = new System.Windows.Forms.Padding(4); + this.Name = "LogForm"; + this.Text = "登录"; + this.Load += new System.EventHandler(this.LogForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.picPhoto)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.TextBox txtUser; + private System.Windows.Forms.Label lblBadge; + private System.Windows.Forms.TextBox txtPassword; + private System.Windows.Forms.PictureBox picPhoto; + private System.Windows.Forms.Button btnLogin; + private System.Windows.Forms.CheckBox chkRemerberPassword; + private System.Windows.Forms.CheckBox chkAutoLogin; + } +} + diff --git a/StormChat/LogForm.cs b/StormChat/LogForm.cs new file mode 100644 index 0000000..c00319b --- /dev/null +++ b/StormChat/LogForm.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using Newtonsoft.Json.Linq; +using Interact; + +namespace StormChat +{ + public partial class LogForm : Form + { + internal static MainForm _mainForm; //主窗口,程序启动时设置 + public LogForm() + { + InitializeComponent(); + } + + private void LogForm_Load(object sender, EventArgs e) + { + StormClient.OnLoginDone += this.LoginDone; + } + private void btnLogin_Click(object sender, EventArgs e) + { + if(!StormClient.Initialize()) + { + MessageBox.Show(this, "连接服务器失败!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + btnLogin.Enabled = false; + StormClient.RequestLogin(txtUser.Text, txtPassword.Text); + } + + //登录结果处理 + private void LoginDone(JObject head, User user) + { + Action f = delegate () + { + btnLogin.Enabled = true; + if (head[Strings.Error].ToString() != "") + { + MessageBox.Show("登录失败:" + head[Strings.Error].ToString()); + return; + } + _mainForm.Opacity = 1; + _mainForm.Show(); + this.Close(); + }; + //处理跨线程调用 + if (this.InvokeRequired) + this.Invoke(f); + else + f.Invoke(); + } + } +} diff --git a/StormChat/LogForm.resx b/StormChat/LogForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/StormChat/LogForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/StormChat/MainForm.Designer.cs b/StormChat/MainForm.Designer.cs new file mode 100644 index 0000000..0f5ec29 --- /dev/null +++ b/StormChat/MainForm.Designer.cs @@ -0,0 +1,111 @@ +namespace StormChat +{ + partial class MainForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.picPhoto = new System.Windows.Forms.PictureBox(); + this.lblName = new System.Windows.Forms.Label(); + this.txtMotto = new System.Windows.Forms.TextBox(); + this.listBox1 = new System.Windows.Forms.ListBox(); + ((System.ComponentModel.ISupportInitialize)(this.picPhoto)).BeginInit(); + this.SuspendLayout(); + // + // picPhoto + // + this.picPhoto.Image = global::StormChat.Properties.Resources.DefaultPhoto; + this.picPhoto.Location = new System.Drawing.Point(16, 20); + this.picPhoto.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.picPhoto.Name = "picPhoto"; + this.picPhoto.Size = new System.Drawing.Size(160, 150); + this.picPhoto.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.picPhoto.TabIndex = 5; + this.picPhoto.TabStop = false; + // + // lblName + // + this.lblName.AutoSize = true; + this.lblName.Font = new System.Drawing.Font("Microsoft YaHei", 24F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.lblName.Location = new System.Drawing.Point(215, 20); + this.lblName.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(170, 52); + this.lblName.TabIndex = 6; + this.lblName.Text = "Mattuy"; + // + // txtMotto + // + this.txtMotto.BackColor = System.Drawing.SystemColors.Control; + this.txtMotto.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.txtMotto.Font = new System.Drawing.Font("SimSun", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.txtMotto.Location = new System.Drawing.Point(215, 91); + this.txtMotto.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.txtMotto.Name = "txtMotto"; + this.txtMotto.Size = new System.Drawing.Size(241, 23); + this.txtMotto.TabIndex = 7; + this.txtMotto.Text = "I am a programer."; + // + // listBox1 + // + this.listBox1.Font = new System.Drawing.Font("SimSun", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.listBox1.FormattingEnabled = true; + this.listBox1.ItemHeight = 20; + this.listBox1.Location = new System.Drawing.Point(16, 195); + this.listBox1.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.listBox1.Name = "listBox1"; + this.listBox1.Size = new System.Drawing.Size(439, 564); + this.listBox1.TabIndex = 8; + // + // MainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(472, 789); + this.Controls.Add(this.listBox1); + this.Controls.Add(this.txtMotto); + this.Controls.Add(this.lblName); + this.Controls.Add(this.picPhoto); + this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.MaximizeBox = false; + this.Name = "MainForm"; + this.Opacity = 0D; + this.Text = "MainForm"; + this.Load += new System.EventHandler(this.MainForm_Load); + ((System.ComponentModel.ISupportInitialize)(this.picPhoto)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.PictureBox picPhoto; + private System.Windows.Forms.Label lblName; + private System.Windows.Forms.TextBox txtMotto; + private System.Windows.Forms.ListBox listBox1; + } +} \ No newline at end of file diff --git a/StormChat/MainForm.cs b/StormChat/MainForm.cs new file mode 100644 index 0000000..1044ec7 --- /dev/null +++ b/StormChat/MainForm.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace StormChat +{ + public partial class MainForm : Form + { + public MainForm() + { + InitializeComponent(); + } + + private void MainForm_Load(object sender, EventArgs e) + { + this.Visible = false; + new LogForm().Show(); + } + } +} diff --git a/StormChat/MainForm.resx b/StormChat/MainForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/StormChat/MainForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/StormChat/Program.cs b/StormChat/Program.cs new file mode 100644 index 0000000..11404d8 --- /dev/null +++ b/StormChat/Program.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace StormChat +{ + static class Program + { + /// + /// 应用程序的主入口点。 + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + LogForm._mainForm = new MainForm(); + Application.Run(LogForm._mainForm); + } + } +} diff --git a/StormChat/Properties/AssemblyInfo.cs b/StormChat/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e7cbb4c --- /dev/null +++ b/StormChat/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("StormChat")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Billows West")] +[assembly: AssemblyProduct("StormChat")] +[assembly: AssemblyCopyright("Copyright © Billows West 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +//将 ComVisible 设置为 false 将使此程序集中的类型 +//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("01903ae6-fdb9-4ff4-8be7-fda238ceb5ad")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, +// 方法是按如下所示使用“*”: : +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.1.0.0")] +[assembly: AssemblyFileVersion("0.1.0.0")] diff --git a/StormChat/Properties/Resources.Designer.cs b/StormChat/Properties/Resources.Designer.cs new file mode 100644 index 0000000..d3ffa6e --- /dev/null +++ b/StormChat/Properties/Resources.Designer.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace StormChat.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StormChat.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap DefaultPhoto { + get { + object obj = ResourceManager.GetObject("DefaultPhoto", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap LogFormBackground { + get { + object obj = ResourceManager.GetObject("LogFormBackground", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/StormChat/Properties/Resources.resx b/StormChat/Properties/Resources.resx new file mode 100644 index 0000000..053d988 --- /dev/null +++ b/StormChat/Properties/Resources.resx @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\pic\DefaultPhoto.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\pic\logFormBackground.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/StormChat/Properties/Settings.Designer.cs b/StormChat/Properties/Settings.Designer.cs new file mode 100644 index 0000000..4f85e24 --- /dev/null +++ b/StormChat/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace StormChat.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/StormChat/Properties/Settings.settings b/StormChat/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/StormChat/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/StormChat/Properties/app.manifest b/StormChat/Properties/app.manifest new file mode 100644 index 0000000..29d0cc2 --- /dev/null +++ b/StormChat/Properties/app.manifest @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + \ No newline at end of file diff --git a/StormChat/StormChat.csproj b/StormChat/StormChat.csproj new file mode 100644 index 0000000..84e4023 --- /dev/null +++ b/StormChat/StormChat.csproj @@ -0,0 +1,130 @@ + + + + + Debug + AnyCPU + {01903AE6-FDB9-4FF4-8BE7-FDA238CEB5AD} + WinExe + Properties + StormChat + StormChat + v4.0 + 512 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + LocalIntranet + + + true + + + Properties\app.manifest + + + + False + ..\Interact\Newtonsoft.Json.dll + + + + + + + + + + + + + + + Form + + + LogForm.cs + + + Form + + + MainForm.cs + + + + + LogForm.cs + + + MainForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + + + + + + + + + + {cef054af-95b7-4b88-934e-02705feea554} + Interact + + + + + \ No newline at end of file diff --git a/StormChat/pic/DefaultPhoto.jpg b/StormChat/pic/DefaultPhoto.jpg new file mode 100644 index 0000000..7a9eab1 Binary files /dev/null and b/StormChat/pic/DefaultPhoto.jpg differ diff --git a/StormChat/pic/LogFormBackground.jpg b/StormChat/pic/LogFormBackground.jpg new file mode 100644 index 0000000..ea8dcfe Binary files /dev/null and b/StormChat/pic/LogFormBackground.jpg differ