个人密码管理器

关键词

  • c#
  • go
  • 本地web

设计思路

用go语言编写本地后台

  • 作用:

    1. 数据持久化。将数据存入sqlite数据库,还有数据的增删改查,

    2. 本地web后端。监听本地1210端口,访问本地1210端口可完成对数据的一系列操作

用c#语言编写程序界面

  • 作用:

    1. 管理后台服务。启动后台,关闭后台。

    2. 与后台交互。通过访问本地端口,实现对数据的一系列操作

代码

完整代码:github/gitee

后台代码实现

web.go
package main

import (
    "database/sql"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"

    // "strconv"
    // "time"

    _ "github.com/mattn/go-sqlite3"
)

const (
    TIMELIMIT = 10
)

type setting struct {
    TIMELIMIT int
}

func main() {
    var st setting

    log.Println("start read setting")

    st.readSetting()

    log.Println("read setting is finish")

    log.Printf("main: starting HTTP server")

    httpServer()

    // var srv *http.Server
    // srv = new(http.Server)
    // srv = httpServer()

    // log.Printf("main: serving for " + strconv.Itoa(st.TIMELIMIT) + " seconds")

    // time.Sleep(time.Duration(st.TIMELIMIT) * time.Second)

    // log.Printf("main: stopping HTTP server")

    // now close the server gracefully ("shutdown")
    // timeout could be given instead of nil as a https://golang.org/pkg/context/
    // if err := srv.Shutdown(nil); err != nil {
    //  panic(err) // failure/timeout shutting down the server gracefully
    // }

    // log.Printf("main: done. exiting")
}

func httpServer() {
    htmlPath := "./index.html"

    srv := &http.Server{Addr: ":1210"}

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Access-Control-Allow-Origin", "http://localhost:1210")
        var data []byte
        var err error
        reqURI := r.RequestURI
        switch reqURI {
        case "/":
            data, err = readFile(htmlPath)
        case "/data":
            data, err = readSql()
        default:
            data, err = readFile("." + reqURI)
        }
        if err == nil {
            w.Write(data)
        }
    })

    if err := srv.ListenAndServe(); err != nil {
        // cannot panic, because this probably is an intentional close
        log.Printf("Httpserver: ListenAndServe() error: %s", err)
    }

    // go func() {
    //  if err := srv.ListenAndServe(); err != nil {
    //      // cannot panic, because this probably is an intentional close
    //      log.Printf("Httpserver: ListenAndServe() error: %s", err)
    //  }
    // }()

    // // returning reference so caller can call Shutdown()
    // return srv
}

func (st *setting) readSetting() {
    b, err := read("./setting.json")
    checkErr(err)
    if err := json.Unmarshal(b, st); err != nil {
        panic(b)
    }
}

func checkErr(err error) {
    if err != nil {
        panic(err)
    }
}

type user struct {
    id       string         `json:"id"`
    place    string         `json:"place"`
    account  string         `json:"account"`
    password string         `json:"password"`
    note     sql.NullString `json:"note"`
}

func (u *user) out() {
    fmt.Println(u.id)
    fmt.Println(u.place)
    fmt.Println(u.account)
    fmt.Println(u.password)
    fmt.Println(u.note)
}

func readSql() ([]byte, error) {
    return getJSON("select * from sercet")
}

func readFile(filepath string) ([]byte, error) {
    return read(filepath)
}

func read(filepath string) ([]byte, error) {
    f, err := os.Open(filepath)
    if err != nil {
        return nil, err
    }
    return ioutil.ReadAll(f)
}

func getJSON(sqlString string) ([]byte, error) {
    db, err := sql.Open("sqlite3", "./sercet.db")
    if err != nil {
        return nil, err
    }

    stmt, err := db.Prepare(sqlString)
    if err != nil {
        return nil, err
    }
    defer stmt.Close() // defer的作用,在打开stmt后,不管后面的代码流程如何影响,它能够被自动关闭。

    rows, err := stmt.Query()
    if err != nil {
        return nil, err
    }
    defer rows.Close() // 同上

    columns, err := rows.Columns() // 返回[]string, error
    if err != nil {
        return []byte(""), err
    }

    count := len(columns)
    tableData := make([]map[string]interface{}, 0)
    values := make([]interface{}, count)
    valuePtrs := make([]interface{}, count)

    for rows.Next() {
        for i := 0; i < count; i++ {
            valuePtrs[i] = &values[i] // 将引用放入数组中
        }
        rows.Scan(valuePtrs...) // 使用数组获取结果,"..."是
        entry := make(map[string]interface{})
        for i, col := range columns { // i是数字,col是数组中对应下标i的值
            var v interface{}
            val := values[i]
            b, ok := val.([]byte) // 类型断言(type assertion),简单来说就是看val的类型是不是[]byte
            if ok {
                v = string(b)
            } else {
                v = val
            }
            entry[col] = v
        }
        tableData = append(tableData, entry)
    }

    return json.Marshal(tableData)
}

界面代码实现

Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PasswordManager
{
    public partial class Form1 : Form
    {
        private Process p;
        private progressForm pf;

        public Form1()
        {
            InitializeComponent();
            pf = new progressForm();
            startWeb();
        }

        private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {

        }

        private void startWeb()
        {
            p = new Process();
            p.StartInfo.FileName = Application.StartupPath + @"\web2\web.exe";
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true; // 标准输入流
            p.StartInfo.RedirectStandardOutput = true; // 标准输出流
            p.StartInfo.RedirectStandardError = true; // 标准错误流
            p.StartInfo.CreateNoWindow = true; // 创建没有窗口
            // 工作目录 = 应用启动路径
            p.StartInfo.WorkingDirectory = Application.StartupPath + @"\web2\";
            p.Start();

            webBrowser1.Url = new Uri("http://localhost:1210/");
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            pf.Show();
            pf.setValue(0);
            Process[] processList = Process.GetProcesses();
            foreach (Process p in processList)
            {
                if (p.ProcessName.ToLower() == "web")
                {
                    pf.setValue(50);
                    p.Kill();
                    break;
                }
            }
            pf.setValue(100);
            pf.Close();
        }

        private void setValue(int n)
        {

        }

        /// <summary>   
        /// 运行DOS命令   
        /// DOS关闭进程命令(ntsd -c q -p PID )PID为进程的ID   
        /// </summary>   
        /// <param name="command"></param>   
        /// <returns></returns>   
        private string RunCmd(string command)
        {
            Process p = new Process();

            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.Arguments = "/c " + command;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;

            p.Start();

            return p.StandardOutput.ReadToEnd();
        }
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容