跳到主要内容

github/tai

公开

Tai · Windows 软件与网站使用时长统计。上游 Planshit/Tai 的源码镜像,非灵栈原创;MIT 许可。来源:https://github.com/Planshit/Tai 。本次为手动同步,暂不提供安装包。

提交记录
修改Core/Librarys/SQLite/SQLiteBuilder.cs+225 −39看文件
@@ -1,6 +1,7 @@
11using System;
22using System.Collections.Generic;
33using System.Data.SQLite;
4新增:using System.Diagnostics;
45using System.IO;
56using System.Linq;
67using System.Reflection;
@@ -36,15 +37,26 @@ namespace Core.Librarys.SQLite
3637 /// 列名
3738 /// </summary>
3839 public string Name { get; set; }
39删除: public string Type { get; set; }
40新增: public DbType Type { get; set; }
4041 public bool PK { get; set; }
41删除: public bool NotNull { get { return !PK; } }
42新增: //public bool NotNull { get { return !PK; } }
4243 }
44新增:
45新增: public enum DbType
46新增: {
47新增: INTEGER,
48新增: datetime,
49新增: nvarchar,
50新增: @int
51新增: }
52新增:
4353 /// <summary>
4454 ///handle sqlite code first
4555 /// </summary>
4656 public class SQLiteBuilder
4757 {
58新增: public static bool IsSelfChecking = true;
59新增:
4860 private System.Data.Entity.Infrastructure.DbModel model;
4961 /// <summary>
5062 /// 连接字符串
@@ -54,6 +66,11 @@ namespace Core.Librarys.SQLite
5466 /// 数据库版本文件
5567 /// </summary>
5668 private string versionFile;
69新增:
70新增: /// <summary>
71新增: /// 数据库文件路径
72新增: /// </summary>
73新增: private string dbFile;
5774 /// <summary>
5875 /// 数据模型
5976 /// </summary>
@@ -71,62 +88,210 @@ namespace Core.Librarys.SQLite
7188
7289 providerManifest = model.ProviderManifest;
7390
74删除: versionFile = connstr.Split('=')[1] + ".version";
91新增: dbFile = connstr.Split('=')[1];
92新增:
93新增: versionFile = $"{dbFile}.version";
94新增:
7595 }
7696 }
7797
78删除: public void Handle()
98新增: /// <summary>
99新增: /// 执行数据库自检
100新增: /// </summary>
101新增: public bool SelfCheck()
79102 {
80103 if (IsHandleDb())
81104 {
82删除: HandleTable();
105新增: bool res = HandleTable();
106新增:
107新增: IsSelfChecking = false;
108新增:
109新增: return res;
83110 }
111新增:
112新增: IsSelfChecking = false;
113新增:
114新增: return true;
84115 }
85116
86117 /// <summary>
87删除: /// 处理表变化(仅处理新增表、新增表字段。不处理表名更改、列名更改、删除)
118新增: /// 处理表变化(仅处理新增表、新增表字段、表结构变化)
88119 /// </summary>
89删除: private void HandleTable()
120新增: private bool HandleTable()
90121 {
91删除: var modelInfos = GetModelInfos();
122新增: try
123新增: {
124新增: // 处理前先复制一份数据库文件以防万一
125新增: string dir = Path.Combine(Path.GetDirectoryName(dbFile), "backup");
126新增: string backupName = Path.Combine(dir, $"data.handle.backup");
127新增: if (!Directory.Exists(dir))
128新增: {
129新增: Directory.CreateDirectory(dir);
130新增: }
131新增: if (File.Exists(backupName))
132新增: {
133新增: File.Delete(backupName);
134新增: }
135新增: File.Copy(dbFile, backupName);
92136
93删除: var modelInfosDb = GetModelInfosForDb();
137新增: var modelInfos = GetModelInfos();
94138
95删除: foreach (var model in modelInfos)
96删除: {
97删除: //表名
98删除: string tableName = model.TableName;
139新增: var modelInfosDb = GetModelInfosForDb();
99140
100删除: var modelInfoDb = modelInfosDb.Where(m => m.TableName == tableName);
101删除: //判断表是否存在
102删除: if (modelInfoDb.Count() <= 0)
141新增: foreach (var model in modelInfos)
103142 {
104删除: //不存在则重新创建表
105删除: string csql = GetCreateTableSQL(model);
106删除: ExecuteNonQuery(csql);
143新增: //表名
144新增: string tableName = model.TableName;
145新增:
146新增: var modelInfoDb = modelInfosDb.Where(m => m.TableName == tableName);
147新增: //判断表是否存在
148新增: if (modelInfoDb.Count() <= 0)
149新增: {
150新增: //不存在则重新创建表
151新增: string csql = GetCreateTableSQL(model);
152新增: ExecuteNonQuery(csql);
153新增: }
154新增: else
155新增: {
156新增: //存在则扫描新字段(*暂时不处理字段的属性变化,只处理新增)
157新增:
158新增: //对应的数据库模型信息
159新增: var modelDb = modelInfoDb.Single();
160新增: //查找差异属性
161新增: foreach (var item in model.Properties)
162新增: {
163新增: if (modelDb.Properties.Where(m => m.Name == item.Name).Count() <= 0)
164新增: {
165新增: string csql = GetCreateColumnSQL(tableName, item);
166新增: ExecuteNonQuery(csql);
167新增: }
168新增: }
169新增:
170新增: }
171新增:
107172 }
108删除: else
173新增:
174新增: HandleVersion1002Migrate();
175新增:
176新增:
177新增: // 处理表字段删除
178新增: foreach (var dbModel in modelInfosDb)
109179 {
110删除: //存在则扫描新字段(*暂时不处理字段的属性变化,只处理新增)
180新增: // 表名
181新增: string tableName = dbModel.TableName;
182新增:
183新增: // 查找对应的实体模型
184新增: var model = modelInfos.Where(m => m.TableName == tableName).FirstOrDefault();
111185
112删除: //对应的数据库模型信息
113删除: var modelDb = modelInfoDb.Single();
114删除: //查找差异属性
115删除: foreach (var item in model.Properties)
186新增: if (model == null)
187新增: {
188新增: // 已删除的模型就从数据库中删除
189新增: //ExecuteNonQuery($"DROP TABLE {tableName}");// 暂时不处理
190新增: }
191新增: else
116192 {
117删除: if (modelDb.Properties.Where(m => m.Name == item.Name).Count() <= 0)
193新增: // 遍历数据库表的属性
194新增:
195新增: bool isDel = false;
196新增:
197新增:
198新增:
199新增: foreach (var dbItem in dbModel.Properties)
118200 {
119删除: string csql = GetCreateColumnSQL(tableName, item);
120删除: ExecuteNonQuery(csql);
201新增: // 判断实体模型是否有字段,没有的话需要重建表
202新增: if (!model.Properties.Where(m => m.Name == dbItem.Name).Any())
203新增: {
204新增: isDel = true;
205新增: break;
206新增: }
207新增:
208新增:
209新增: }
210新增: if (isDel)
211新增: {
212新增: // 模型字段
213新增: string field = string.Join(",", model.Properties.Select(m => m.Name).ToArray());
214新增:
215新增: // 临时表名
216新增: string tempName = $"{tableName}_temp_{DateTime.Now.ToString("yyyyMMddHHmmss")}";
217新增:
218新增: // 创建一个新表
219新增: ExecuteNonQuery(GetCreateTableSQL(model, tempName));
220新增:
221新增: //// 转移数据
222新增: ExecuteNonQuery($"INSERT INTO {tempName}({field}) SELECT {field} FROM {tableName}");
223新增:
224新增:
225新增: // 删除旧表
226新增: ExecuteNonQuery($"drop table {tableName}");
227新增:
228新增:
229新增: // 重新命名临时表
230新增: ExecuteNonQuery($"alter table {tempName} rename to {tableName}");
121231 }
122232 }
123233
124234 }
235新增: return true;
236新增: }
237新增: catch (Exception ex)
238新增: {
239新增: Logger.Error($"SQLiteBuilder handle fail!Exception Message:{ex.Message}");
240新增: return false;
241新增: }
242新增: }
243新增:
244新增:
245新增: /// <summary>
246新增: /// 数据迁移,1.0.0.2升级1.0.0.3时需要转移表数据
247新增: /// </summary>
248新增: private void HandleVersion1002Migrate()
249新增: {
250新增: //if (ExecuteNonQuery("select count(*) from sqlite_master where type='table' and name='AppModels'") != 0)
251新增: //{
252新增: // return;
253新增: //}
254新增: ExecuteNonQuery($"insert into AppModels(ID,Name,Description,File,TotalTime) select null,ProcessName as Name,ProcessDescription as Description,File,sum(Time) as TotalTime from DailyLogModels where 1=1 GROUP BY Name");
255新增:
256新增: using (var con = new SQLiteConnection(connstr))
257新增: {
258新增: con.Open();
259新增: using (var cmd = new SQLiteCommand(con))
260新增: {
261新增: cmd.CommandText = $"select ID,Name,Description from AppModels GROUP BY Name";
262新增:
263新增: List<string> sqlList = new List<string>();
264新增:
265新增: using (var rd = cmd.ExecuteReader())
266新增: {
267新增: while (rd.Read())
268新增: {
269新增: var ID = rd[0];
270新增: var Name = rd[1].ToString();
271新增: var Description = rd[2].ToString();
272新增:
273新增: var icon = Iconer.Get(Name, Description);
274新增:
275新增: sqlList.Add($"update DailyLogModels set AppModelID={ID} where ProcessName='{Name}'");
276新增: sqlList.Add($"update HoursLogModels set AppModelID={ID} where ProcessName='{Name}'");
277新增:
278新增:
279新增: sqlList.Add($"update AppModels set IconFile='{icon}' where ID={ID}");
280新增: }
281新增: }
125282
283新增: cmd.CommandText = string.Join("; ", sqlList.ToArray());
284新增: cmd.ExecuteNonQuery();
285新增: }
126286 }
287新增:
127288 }
128289
129290 #region 是否需要处理
291新增: /// <summary>
292新增: /// 判断是否需要处理数据,比对core程序集版本号
293新增: /// </summary>
294新增: /// <returns></returns>
130295 private bool IsHandleDb()
131296 {
132297 string dir = Path.GetDirectoryName(versionFile);
@@ -136,22 +301,24 @@ namespace Core.Librarys.SQLite
136301 }
137302
138303 bool f = File.Exists(versionFile);
139删除: string appVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
304新增:
305新增: // core程序集版本号
306新增: string coreVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
140307 if (f)
141308 {
142309 //存在版本文件对比是否需要更新
143310 string dbVersion = File.ReadAllText(versionFile);
144删除: if (dbVersion != appVersion)
311新增: if (dbVersion != coreVersion)
145312 {
146313 //版本不一致需要更新
147删除: File.WriteAllText(versionFile, appVersion);
314新增: File.WriteAllText(versionFile, coreVersion);
148315 return true;
149316 }
150317 //不需要更新
151318 return false;
152319 }
153320
154删除: File.WriteAllText(versionFile, appVersion);
321新增: File.WriteAllText(versionFile, coreVersion);
155322 return true;
156323 }
157324
@@ -166,7 +333,12 @@ namespace Core.Librarys.SQLite
166333 /// <returns></returns>
167334 private string GetCreateColumnSQL(string tableName, IModelProperties properties)
168335 {
169删除: string typeDefault = properties.NotNull ? properties.Type == "int" ? "NOT NULL DEFAULT 0" : "NOT NULL DEFAULT ''" : "";
336新增: string typeDefault = !properties.PK ? properties.Type == DbType.@int ? "NULL DEFAULT 0" : "NULL DEFAULT ''" : "";
337新增:
338新增: if (properties.PK)
339新增: {
340新增: properties.Type = DbType.INTEGER;
341新增: }
170342 return $"ALTER table {tableName} ADD COLUMN [{properties.Name}] {properties.Type} {typeDefault}";
171343 }
172344 #endregion
@@ -177,14 +349,23 @@ namespace Core.Librarys.SQLite
177349 /// </summary>
178350 /// <param name="model">模型信息</param>
179351 /// <returns></returns>
180删除: private string GetCreateTableSQL(IModelInfo model)
352新增: private string GetCreateTableSQL(IModelInfo model, string tableName = null)
181353 {
182删除: string sql = $"CREATE TABLE \"{model.TableName}\" (";
354新增: tableName = string.IsNullOrEmpty(tableName) ? model.TableName : tableName;
355新增:
356新增: string sql = $"CREATE TABLE \"{tableName}\" (";
183357 foreach (var p in model.Properties)
184358 {
185删除: string add = p.PK ? $"{p.Type} PRIMARY KEY" : p.Type + (p.NotNull ? " NOT NULL" : "");
359新增: string typeDefault = p.Type == DbType.@int ? " NULL DEFAULT 0" : " NULL DEFAULT ''";
360新增: if (p.PK)
361新增: {
362新增: typeDefault = "";
363新增: p.Type = DbType.INTEGER;
364新增: }
365新增:
366新增: string add = p.PK ? $"{p.Type} PRIMARY KEY" : p.Type.ToString();
186367 string addChar = p == model.Properties[0] ? "" : ",";
187删除: sql += $"{addChar}[{p.Name}] {add}";
368新增: sql += $"{addChar}[{p.Name}] {add}{typeDefault}";
188369 }
189370 sql += ")";
190371 return sql;
@@ -238,11 +419,13 @@ namespace Core.Librarys.SQLite
238419 //属性获取
239420 foreach (var p in model.Properties)
240421 {
422新增: Enum.TryParse(p.TypeName, out DbType dbType);
423新增:
241424 ps.Add(new IModelProperties()
242425 {
243426 Name = p.Name,
244427 PK = p.IsStoreGeneratedIdentity,
245删除: Type = p.TypeName == "int" && p.IsStoreGeneratedIdentity ? "INTEGER" : p.TypeName
428新增: Type = dbType
246429 });
247430 }
248431 result.Add(i);
@@ -303,7 +486,8 @@ namespace Core.Librarys.SQLite
303486 {
304487 var mp = new IModelProperties();
305488 mp.Name = rd["name"].ToString();
306删除: mp.Type = rd["type"].ToString();
489新增: Enum.TryParse(rd["type"].ToString(), out DbType dbType);
490新增: mp.Type = dbType;
307491 mp.PK = rd["pk"].ToString() == "1";
308492 result.Add(mp);
309493 }
@@ -334,6 +518,8 @@ namespace Core.Librarys.SQLite
334518
335519 }
336520 }
521新增:
522新增:
337523 }
338524
339525}
文件末尾没有换行
修改Core/Librarys/SQLite/StatisticContext.cs+2 −1看文件
@@ -19,6 +19,7 @@ namespace Core.Librarys.SQLite
1919 /// 时段数据
2020 /// </summary>
2121 public DbSet<HoursLogModel> HoursLog { get; set; }
22新增: public DbSet<AppModel> App { get; set; }
2223
2324 // public StatisticContext(string n)
2425 //: base("StatisticContext")
@@ -37,7 +38,7 @@ namespace Core.Librarys.SQLite
3738 protected override void OnModelCreating(DbModelBuilder modelBuilder)
3839 {
3940 var model = modelBuilder.Build(Database.Connection);
40删除: new SQLiteBuilder(model).Handle();
41新增: new SQLiteBuilder(model).SelfCheck();
4142 }
4243 }
4344}
文件末尾没有换行
修改Core/Servicers/Instances/Main.cs+69 −12看文件
@@ -1,6 +1,7 @@
11using Core.Enums;
22using Core.Librarys;
33using Core.Librarys.SQLite;
4新增:using Core.Models;
45using Core.Models.Config;
56using Core.Models.Config.Link;
67using Core.Servicers.Interfaces;
@@ -118,24 +119,40 @@ namespace Core.Servicers.Instances
118119
119120 public void Run()
120121 {
121删除: // 加载应用配置(确保配置文件最先加载
122删除: appConfig.Load();
123删除: config = appConfig.GetConfig();
122新增: Task.Run(() =>
123新增: {
124新增: Debug.WriteLine("start");
125新增: // 数据库自检
126新增: using (var db = new StatisticContext())
127新增: {
128新增: db.Database.ExecuteSqlCommand("select count(*) from sqlite_master where type='table' and name='tai'");
129新增: }
130新增: // 加载app信息
131新增: data.LoadAppList();
132新增:
133新增: // 加载应用配置(确保配置文件最先加载
134新增: appConfig.Load();
135新增: config = appConfig.GetConfig();
124136
125删除: // 日期变化观察
126删除: dateObserver.Start();
137新增: // 日期变化观察
138新增: dateObserver.Start();
127139
128删除: // 启动进程观察
129删除: observer.Start();
140新增: // 启动进程观察
141新增: observer.Start();
130142
131删除: // 启动睡眠监测
132删除: sleepdiscover.Start();
143新增: // 启动睡眠监测
144新增: sleepdiscover.Start();
145新增: Debug.WriteLine("over!");
146新增:
147新增: });
133148
134149 }
135150
136151 public void Exit()
137152 {
138153 observer?.Stop();
154新增:
155新增: data.SaveAppChanges();
139156 }
140157
141158
@@ -153,6 +170,9 @@ namespace Core.Servicers.Instances
153170 activeProcess = null;
154171 //activeSeconds = 0;
155172 //activeTimer.Stop();
173新增:
174新增: // 更新app数据
175新增: data.SaveAppChanges();
156176 }
157177 else if (sleepStatus == SleepStatus.Wake)
158178 {
@@ -161,8 +181,46 @@ namespace Core.Servicers.Instances
161181 }
162182 }
163183
184新增:
185新增: /// <summary>
186新增: /// 检查焦点app是否已经在库
187新增: /// </summary>
188新增: /// <param name="processName"></param>
189新增: /// <param name="description"></param>
190新增: /// <param name="file"></param>
191新增: private void CheckApp(string processName, string description, string file)
192新增: {
193新增: if (string.IsNullOrEmpty(file) || string.IsNullOrEmpty(processName))
194新增: {
195新增: return;
196新增: }
197新增:
198新增:
199新增: if (!config.Behavior.IgnoreProcessList.Contains(processName)
200新增: && !IgnoreProcess.Contains(processName))
201新增: {
202新增: AppModel app = data.GetApp(processName);
203新增: if (app == null)
204新增: {
205新增: // 提取icon
206新增: string iconFile = Iconer.ExtractFromFile(file, processName, description);
207新增:
208新增: data.AddApp(new AppModel()
209新增: {
210新增: Name = processName,
211新增: Description = description,
212新增: File = file,
213新增: CategoryID = 0,
214新增: IconFile = iconFile,
215新增: });
216新增: }
217新增: }
218新增: }
219新增:
164220 private void Observer_OnAppActive(string processName, string description, string file)
165221 {
222新增: CheckApp(processName, description, file);
223新增:
166224 if (activeProcess != processName && activeProcessFile != file)
167225 {
168226 UpdateTime();
@@ -185,8 +243,7 @@ namespace Core.Servicers.Instances
185243 // activeTimer.Start();
186244 //}
187245
188删除: // 提取icon
189删除: Iconer.ExtractFromFile(file, processName, description);
246新增:
190247 }
191248 else
192249 {
@@ -266,7 +323,7 @@ namespace Core.Servicers.Instances
266323
267324
268325
269删除: Logger.Info("【"+sleepStatus + "】进程:" + activeProcess + " 更新时间:" + seconds + ",开始时间:" + activeStartTime.ToString() + ",当前时间:" + DateTime.Now.ToString());
326新增: Logger.Info("【" + sleepStatus + "】进程:" + activeProcess + " 更新时间:" + seconds + ",开始时间:" + activeStartTime.ToString() + ",当前时间:" + DateTime.Now.ToString());
270327
271328
272329 data.Set(activeProcess, activeProcessDescription, activeProcessFile, seconds);
修改UI/App.xaml.cs+31 −5看文件
@@ -1,4 +1,5 @@
11using Core.Librarys;
2新增:using Core.Librarys.SQLite;
23using Core.Servicers.Instances;
34using Core.Servicers.Interfaces;
45using Microsoft.Extensions.DependencyInjection;
@@ -40,6 +41,10 @@ namespace UI
4041 private DefaultWindow mainWindow;
4142 public App()
4243 {
44新增: InitStatusBarIcon();
45新增:
46新增: WatchStatus();
47新增:
4348 DispatcherUnhandledException += App_DispatcherUnhandledException;
4449
4550 var serviceCollection = new ServiceCollection();
@@ -50,6 +55,13 @@ namespace UI
5055 protected override void OnExit(ExitEventArgs e)
5156 {
5257 base.OnExit(e);
58新增:
59新增: var data = serviceProvider.GetService<IData>();
60新增:
61新增: data.SaveAppChanges();
62新增:
63新增: Logger.Save(true);
64新增:
5365 statusBarIcon.Visible = false;
5466 }
5567 private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
@@ -57,6 +69,8 @@ namespace UI
5769 // 记录崩溃错误
5870 Logger.Error("[程序崩溃异常] " + e.Exception.Message);
5971
72新增: Logger.Save(true);
73新增:
6074 e.Handled = true;
6175
6276 Shutdown();
@@ -95,8 +109,8 @@ namespace UI
95109 CreateStatusBarIconMenu();
96110
97111 statusBarIcon = new System.Windows.Forms.NotifyIcon();
98删除: statusBarIcon.Text = "Tai!";
99删除: Stream iconStream = GetResourceStream(new Uri("pack://application:,,,/Tai;component/Resources/Icons/tai32.ico")).Stream;
112新增: statusBarIcon.Text = "Tai! [数据库自检中...请稍后]";
113新增: Stream iconStream = GetResourceStream(new Uri("pack://application:,,,/Tai;component/Resources/Icons/taibusy.ico")).Stream;
100114 statusBarIcon.Icon = new Icon(iconStream);
101115 //statusBarIcon.Icon = System.Drawing.Icon.ExtractAssociatedIcon(System.Reflection.Assembly.GetEntryAssembly().ManifestModule.Name);
102116
@@ -106,7 +120,7 @@ namespace UI
106120 }
107121 private void NotifyIcon_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
108122 {
109删除: if (e.Button == System.Windows.Forms.MouseButtons.Right)
123新增: if (e.Button == System.Windows.Forms.MouseButtons.Right && !SQLiteBuilder.IsSelfChecking)
110124 {
111125 //右键单击弹出托盘菜单
112126 contextMenu.IsOpen = true;
@@ -114,7 +128,7 @@ namespace UI
114128 }
115129 private void NotifyIcon_MouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
116130 {
117删除: if (e.Button == System.Windows.Forms.MouseButtons.Left)
131新增: if (e.Button == System.Windows.Forms.MouseButtons.Left && !SQLiteBuilder.IsSelfChecking)
118132 {
119133 //双击托盘图标显示主窗口
120134 ShowMainWindow();
@@ -205,7 +219,6 @@ namespace UI
205219 // 创建保活窗口
206220 keepaliveWindow = new HideWindow();
207221
208删除: InitStatusBarIcon();
209222 }
210223
211224 private void ShowMainWindow()
@@ -227,5 +240,18 @@ namespace UI
227240 mainWindow.Show();
228241 mainWindow.Activate();
229242 }
243新增:
244新增: private async void WatchStatus()
245新增: {
246新增: await Task.Run(() =>
247新增: {
248新增: while (SQLiteBuilder.IsSelfChecking)
249新增: {
250新增: }
251新增: statusBarIcon.Text = "Tai!";
252新增: Stream iconStream = GetResourceStream(new Uri("pack://application:,,,/Tai;component/Resources/Icons/tai32.ico")).Stream;
253新增: statusBarIcon.Icon = new Icon(iconStream);
254新增: });
255新增: }
230256 }
231257}