软件发布及追溯系统.md 6.9 KB

软件发布及追溯系统

项目背景

随着产品不断升级,产品复杂度不断升级,软件烧录和写入技术难度和产品使用的涉及面及软件更新频次不断增加,以往老的管理方式已经无法支撑目前的软件管理的新常态要求

近期集团内各家工厂的几个软件重大投诉如软件版本代码写错和客户使用的IP地址以及ECU代码写错问题频发,引起客户强烈不满和管理层的高度重视

经过讨论,拟在集团工厂层面导入“软件发布及追溯系统”,对嵌入式软件的发布和生产使用进行全面管控

image-20231017191643319

人员情况

由我本人为主要开发人员,项目管理由经理把控。

技术栈

前端:Vue2 Quasar \ 后端:Java Mybatis Plus SpringBoot \ 中间件:Redis \ 文件上传:阿里云OSS \ 数据库:SqlServer \ 其他:C# WindowsService后台程序

计划用时

cinwell website

主要工作

负责前期需求调研,后端框架搭建,数据库建模,基础代码开发,Vue前端框架搭建,页面功能开发。 以及核心功能:软件发布上传,下载,推送,通知等功能开发。 包括进度汇报等。

问题与难点

集团领导派发的项目经理影响力不够,项目难以在TC(技术中心)推进,导致项目在一段时间内停滞,需求反复变更。

成果

一期UAT测试通过,交付客户IT团队进行维护。

预览(初版-测试数据)

软件上传界面(测试数据) Alt text

Alt text

产品簇界面(测试数据) Alt text

详情回顾 Alt text

代码片段

C# 下载软件包

using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Aliyun.OSS;
using Aliyun.OSS.Common;
using CiemisDownload.Entity;
using CiemisDownload.Helper;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace CiemisDownload
{
    public class DownloadWorker : BackgroundService
    {
        private readonly ILogger<DownloadWorker> _logger;

        private ClientService clientService;


        public DownloadWorker(ILogger<DownloadWorker> logger)
        {
            _logger = logger;
            clientService = ClientService.GetInstance();
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("ping...");

                try
                {
                    //List<DownloadItem> result = await clientService.GetDownloadUrls().ConfigureAwait(result => _logger.LogInformation()) ;
                    List<DownloadItem> result = await clientService.GetDownloadUrls();
                    if (result.Count > 0)
                    {
                        Sts sts = await clientService.GetStsAsync();
                        DownloadFile(sts, result);
                    }
                }
                catch (Exception e)
                {
                    _logger.LogError(e.Message);
                }

                await Task.Delay(1000, stoppingToken);
            }
        }

        /**
         * 创建下载信息文件
         */
        private void CreateDownloadFile(DownloadItem item)
        {
            string downloadPath = ConfigurationManager.AppSettings["DownloadPath"];
            string savePath = downloadPath + item.burnAfterItemCode + "\\";
            string filePath = savePath + "\\" + "point.d";
            Directory.CreateDirectory(savePath);
            if (!File.Exists(filePath))
            {
                FileStream fs1 = new FileStream(filePath, FileMode.Create, FileAccess.Write);
                StreamWriter sw = new StreamWriter(fs1);
                sw.WriteLine(JsonConvert.SerializeObject(item.point)); //开始写入值
                sw.Close();
                fs1.Close();
            }
        }


        private void DownloadFile(Sts sts, List<DownloadItem> result)
        {
            new Task(() =>
            {
                var client = new OssClient("oss-cn-shanghai.aliyuncs.com", "LTAI5tQgUn4M9Pw8otJX4Evq",
                    "vLtqLvGhEeYmhJS5P5ypO78W1xccd6");

                string downloadPath = ConfigurationManager.AppSettings["DownloadPath"];
                try
                {
                    // 
                    foreach (DownloadItem item in result)
                    {
                        CreateDownloadFile(item);
                        item.urls.ForEach((url) =>
                        {
                            _logger.LogInformation("/" + url.url);
                            _logger.LogInformation(downloadPath + url.fileName);
                            var savePath = downloadPath + item.burnAfterItemCode + "\\";


                            Directory.CreateDirectory(savePath);


                            DownloadObjectRequest request = new DownloadObjectRequest(sts.Bucket, url.url,
                                savePath + url.fileName, "E:\\ciemis\\checkpoint\\")
                            {
                                // 指定下载的分片大小。
                                PartSize = 8 * 1024 * 1024,
                                // 指定并发线程数。
                                ParallelThreadCount = 3
                            };
                            request.StreamTransferProgress += StreamProgressCallback;

                            // 断点续传下载。
                            client.ResumableDownloadObject(request);
                        });
                        int success = clientService.DownloadCompleteCallback(item.point.softwareId.ToString())
                            .Result;
                        _logger.LogInformation("下载完成:{0}", success);
                    }
                }
                catch (OssException ex)
                {
                    _logger.LogError("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
                        ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
                }
                catch (Exception ex)
                {
                    _logger.LogError("Failed with error info: {0}", ex.Message);
                }
            }).Start();
        }

        private  void StreamProgressCallback(object sender, StreamTransferProgressArgs args)
        {
           _logger.LogInformation("ProgressCallback - Progress: {0}%, TotalBytes:{1}, TransferredBytes:{2} ",
                args.TransferredBytes * 100 / args.TotalBytes, args.TotalBytes, args.TransferredBytes);
        }
    }
}