From bb80bdf65242b17f0d30c2587efb7a5709869c9b Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Sat, 31 Aug 2024 20:14:59 +0900 Subject: [PATCH 01/26] =?UTF-8?q?HTTPS-53=20<=20=EC=A4=91=EA=B0=84=20?= =?UTF-8?q?=EC=9E=91=EC=97=85=20=EB=B0=B1=EC=97=85(=EC=95=88=EC=93=B8?= =?UTF-8?q?=EA=B1=B0)=20:=20Queue=20=ED=98=95=ED=83=9C=EB=A1=9C=20?= =?UTF-8?q?=EC=9E=91=EC=97=85=EC=9D=84=20=EC=B2=98=EB=A6=AC=ED=95=B4?= =?UTF-8?q?=EB=B3=B4=EB=8F=84=EB=A1=9D=20=EB=A7=8C=EB=93=A4=EC=97=88?= =?UTF-8?q?=EC=9C=BC=EB=82=98=20=EB=B9=84=ED=9A=A8=EC=9C=A8=EC=A0=81?= =?UTF-8?q?=EC=9D=B8=20=EB=93=AF.=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 2 + Core/health_manager.go | 80 ++++++++++ Model/AgentStatus.go | 203 +++++++++++++++++++++++++ Model/AgentStatus_test.go | 84 +++++++++++ Model/ApplicationDB.go | 292 ++++++++++++++++++++++++++++++++++++ Model/ApplicationDB_test.go | 195 ++++++++++++++++++++++++ Model/nosqldb.go | 42 ++++++ PacketQueue.go | 3 + app.go | 168 ++++++++++++++++++++- go.mod | 3 + go.sum | 6 + 11 files changed, 1070 insertions(+), 8 deletions(-) create mode 100644 .env create mode 100644 Core/health_manager.go create mode 100644 Model/AgentStatus.go create mode 100644 Model/AgentStatus_test.go create mode 100644 Model/ApplicationDB.go create mode 100644 Model/ApplicationDB_test.go create mode 100644 Model/nosqldb.go create mode 100644 PacketQueue.go diff --git a/.env b/.env new file mode 100644 index 0000000..a845f51 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +SERVERPROT=8080 +CHECKHEALTHPORT=8081 diff --git a/Core/health_manager.go b/Core/health_manager.go new file mode 100644 index 0000000..e54a6c0 --- /dev/null +++ b/Core/health_manager.go @@ -0,0 +1,80 @@ +package Core + +// 이거 보세요 -> https://d2.naver.com/helloworld/8588537 +import ( + "encoding/json" + "github.com/your/repo/Model" + "net" + "os" + "strconv" +) + +type HealthMsg struct { + UUID string `json:"uuid"` + Status int `json:"status"` +} + +/* +Let Check Example +refer : https://gist.github.com/miguelmota/01ba5131838ae31947ac9b03e57f3773 +*/ +func Heartbeat() { + + // UDP 열기 : HealthCheck + port, err := strconv.Atoi(os.Getenv("PORT")) + conn, err := net.ListenUDP("udp", &net.UDPAddr{ + Port: port, + IP: net.ParseIP("0.0.0.0"), + }) + if err != nil { + panic(err) + } + + go func() { + for { + message := make([]byte, 1024) + n, _, err := conn.ReadFromUDP(message[:]) + if err != nil { + panic(err) + } + if n == 0 { + continue + } + + hmsg := &HealthMsg{} + // json 역질렬화, Unmarshal + err = json.Unmarshal(message[:n], &hmsg) + if err != nil { + panic(err) + } + + agtstatdb := Model.NewAgentStatusDB() + + agtstatRcrd := Model.AgentStatusRecord{ + UUID: hmsg.UUID, + Status: getStatusType(hmsg.Status), + } + + err = agtstatdb.UpdateRecord(&agtstatRcrd) + if err != nil { + panic(err) // 에러처리를 바꿔야함 + } + } + + defer conn.Close() + }() + +} + +func getStatusType(status int) Model.AgentStatus { + + switch status { + case 0: + return Model.Running + case 1: + return Model.Waiting + case 2: + return Model.Stopping + } + return Model.Stopping +} diff --git a/Model/AgentStatus.go b/Model/AgentStatus.go new file mode 100644 index 0000000..2b8914b --- /dev/null +++ b/Model/AgentStatus.go @@ -0,0 +1,203 @@ +package Model + +import ( + "fmt" + "time" +) + +/* +agent 의 상태 Status 는 총 3가지로 나뉜다. + +Running : 동작중인 상태 +waiting : 대기중인 상태 +Stopping : 정지후 사라지기 전에 상태 +*/ +type AgentStatus int + +const ( + Running AgentStatus = iota // 동작 중인 상태 + Waiting // 대기 중인 상태 + Stopping // 정지 후 사라지기 전의 상태 +) + +/* +해당 코드를 빠른 코드 작성을 위해서 Chatgpt 가 작성후 허남정 연구원이 검토하는 형태로 만들었습니다. +*/ + +// AgentStatus를 문자열로 변환하는 메서드를 구현합니다. +func (s AgentStatus) String() string { + switch s { + case Running: + return "Running" + case Waiting: + return "Waiting" + case Stopping: + return "Stopping" + default: + return "Unknown" + } +} + +type AgentStatusDB struct { + dbName string +} + +type AgentStatusRecord struct { + ID int + UUID string + Status AgentStatus + CreatedAt time.Time + UpdatedAt time.Time +} + +// NewAgentStatusDB creates a new instance of AgentStatusDB with the default table name. +func NewAgentStatusDB() *AgentStatusDB { + return &AgentStatusDB{dbName: "AgentStatus"} +} + +// CreateTable creates the AgentStatus table if it does not exist. +func (s *AgentStatusDB) CreateTable() error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + sqlStmt := ` + CREATE TABLE IF NOT EXISTS %s ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + uuid TEXT NOT NULL UNIQUE, + status int, + createAt DATETIME DEFAULT CURRENT_TIMESTAMP, + updateAt DATETIME DEFAULT CURRENT_TIMESTAMP + ); + ` + + sqlStmt = fmt.Sprintf(sqlStmt, s.dbName) + + _, err = db.Exec(sqlStmt) + if err != nil { + return err + } + + sqlTrigger := fmt.Sprintf(` + CREATE TRIGGER IF NOT EXISTS update_ModificationTime + AFTER UPDATE ON %s + FOR EACH ROW + BEGIN + UPDATE %s SET + updateAt = CURRENT_TIMESTAMP + WHERE id = NEW.id; + END; + `, s.dbName, s.dbName) + + _, err = db.Exec(sqlTrigger) + if err != nil { + return err + } + + return nil +} + +// InsertRecord inserts a new record into the AgentStatus table. +func (s *AgentStatusDB) InsertRecord(data *AgentStatusRecord) error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`INSERT INTO %s (uuid, status) VALUES (?, ?)`, s.dbName) + stmt, err := db.Prepare(query) + if err != nil { + return err + } + defer stmt.Close() + + _, err = stmt.Exec(data.UUID, data.Status) + if err != nil { + return err + } + + return nil +} + +// SelectRecords retrieves all records from the AgentStatus table. +func (s *AgentStatusDB) SelectRecords() ([]AgentStatusRecord, error) { + db, err := getDBPtr() + if err != nil { + return nil, err + } + defer db.Close() + + query := fmt.Sprintf(`SELECT id, uuid, status, createAt, updateAt FROM %s`, s.dbName) + rows, err := db.Query(query) + if err != nil { + return nil, err + } + defer rows.Close() + + var records []AgentStatusRecord + for rows.Next() { + var record AgentStatusRecord + err := rows.Scan(&record.ID, &record.UUID, &record.Status, &record.CreatedAt, &record.UpdatedAt) + if err != nil { + return nil, err + } + records = append(records, record) + } + + return records, nil +} + +// UpdateRecord updates the status of a record identified by its UUID. +func (s *AgentStatusDB) UpdateRecord(data *AgentStatusRecord) error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`UPDATE %s SET status = ? WHERE uuid = ?`, s.dbName) + _, err = db.Exec(query, data.Status, data.UUID) + if err != nil { + return err + } + + return nil +} + +// DeleteRecord deletes a record from the AgentStatus table based on its UUID. +func (s *AgentStatusDB) DeleteRecord(uuid string) error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`DELETE FROM %s WHERE uuid = ?`, s.dbName) + _, err = db.Exec(query, uuid) + if err != nil { + return err + } + + return nil +} + +// ExistRecord checks if at least one record exists in the AgentStatus table. +func (s *AgentStatusDB) ExistRecord() (bool, error) { + db, err := getDBPtr() + if err != nil { + return false, err + } + defer db.Close() + + query := fmt.Sprintf(`SELECT EXISTS(SELECT 1 FROM %s)`, s.dbName) + var exists bool + err = db.QueryRow(query).Scan(&exists) + if err != nil { + return false, err + } + + return exists, nil +} diff --git a/Model/AgentStatus_test.go b/Model/AgentStatus_test.go new file mode 100644 index 0000000..b3621bc --- /dev/null +++ b/Model/AgentStatus_test.go @@ -0,0 +1,84 @@ +package Model + +import ( + "testing" + "time" +) + +func TestAgentStatusDB(t *testing.T) { + // 새로운 DB 인스턴스 생성 + db := NewAgentStatusDB() + + // 테이블 생성 테스트 + if err := db.CreateTable(); err != nil { + t.Fatalf("Failed to create table: %v", err) + } + + // 테스트 데이터 생성 + record := &AgentStatusRecord{ + UUID: "test-uuid", + Status: Running, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + // InsertRecord 테스트 + if err := db.InsertRecord(record); err != nil { + t.Fatalf("Failed to insert record: %v", err) + } + + // SelectRecords 테스트 - 삽입 후 조회 + records, err := db.SelectRecords() + if err != nil { + t.Fatalf("Failed to select records: %v", err) + } + + if len(records) != 1 { + t.Fatalf("Expected 1 record, got %d", len(records)) + } + + if records[0].UUID != record.UUID || records[0].Status != record.Status { + t.Fatalf("Record mismatch: expected %v, got %v", record, records[0]) + } + + // UpdateRecord 테스트 - 상태 변경 + record.Status = Stopping + if err := db.UpdateRecord(record); err != nil { + t.Fatalf("Failed to update record: %v", err) + } + + // 업데이트 후 다시 조회 + updatedRecords, err := db.SelectRecords() + if err != nil { + t.Fatalf("Failed to select records after update: %v", err) + } + + if updatedRecords[0].Status != Stopping { + t.Fatalf("Expected status 'inactive', got '%s'", updatedRecords[0].Status) + } + + // DeleteRecord 테스트 + if err := db.DeleteRecord(record.UUID); err != nil { + t.Fatalf("Failed to delete record: %v", err) + } + + // 삭제 후 조회하여 레코드가 없는지 확인 + finalRecords, err := db.SelectRecords() + if err != nil { + t.Fatalf("Failed to select records after delete: %v", err) + } + + if len(finalRecords) != 0 { + t.Fatalf("Expected 0 records, got %d", len(finalRecords)) + } + + // ExistRecord 테스트 - 데이터가 없는 상태에서 확인 + exists, err := db.ExistRecord() + if err != nil { + t.Fatalf("Failed to check if record exists: %v", err) + } + + if exists { + t.Fatalf("Expected no records to exist, but some do") + } +} diff --git a/Model/ApplicationDB.go b/Model/ApplicationDB.go new file mode 100644 index 0000000..9e946ba --- /dev/null +++ b/Model/ApplicationDB.go @@ -0,0 +1,292 @@ +package Model + +import ( + "fmt" + "github.com/yusufpapurcu/wmi" + "log" + "strings" + "time" +) + +type ApplicationDB struct { + dbName string +} + +func NewApplicationDB() (metaTable *ApplicationDB) { + appDB := &ApplicationDB{"Application"} + return appDB +} + +type DapplicationDB struct { + ID int // 내부 ID, 자동 증가 + AgentUUID string + Name string // 제품 이름 + Version string // 제품 버전 + Language string // 제품의 언어 + Vendor string // 제품 공급자 + InstallDate2 string // 설치 날짜 + InstallLocation string // 패키지 설치 위치 + InstallSource string // 설치 소스 위치 + PackageName string // 원래 패키지 이름 + PackageCode string // 패키지 식별자 + RegCompany string // 제품을 사용하는 것으로 등록된 회사 이름 + RegOwner string // 제품을 사용하는 것으로 등록된 사용자 이름 + URLInfoAbout string // 제품에 대한 정보가 제공되는 URL + Description string // 제품 설명 + isDeleted bool + CreateAt time.Time // 레코드 생성 시간 + UpdateAt time.Time // 레코드 업데이트 시간 + deletedAt time.Time +} + +func (a *ApplicationDB) createTable() error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + sqlStmt := ` + CREATE TABLE IF NOT EXISTS %s ( + id INTEGER PRIMARY KEY AUTOINCREMENT, -- 내부 ID, 자동 증가 + AgentUUID VARCHAR(255), + Name VARCHAR(255), -- 제품 이름 + Version VARCHAR(50), -- 제품 버전 + Language VARCHAR(10), -- 제품의 언어 + Vendor VARCHAR(255), -- 제품 공급자 + InstallDate2 VARCHAR(20), -- 설치 날짜 + InstallLocation TEXT, -- 패키지 설치 위치 + InstallSource TEXT, -- 설치 소스 위치 + PackageName VARCHAR(255), -- 원래 패키지 이름 + PackageCode VARCHAR(255) UNIQUE NOT NULL, -- 패키지 식별자 UUID + RegCompany VARCHAR(255), -- 제품을 사용하는 것으로 등록된 회사 이름 + RegOwner VARCHAR(255), -- 제품을 사용하는 것으로 등록된 사용자 이름 + URLInfoAbout TEXT, -- 제품에 대한 정보가 제공되는 URL + Description TEXT, -- 제품 설명 + isDeleted bool DEFAULT FALSE, -- apllication 제거 여부를 파악함 + createAt DATETIME DEFAULT CURRENT_TIMESTAMP, -- 레코드 생성 시간 + updateAt DATETIME DEFAULT CURRENT_TIMESTAMP, -- 레코드 업데이트 시간 + deletedAt DATETIME DEFAULT CURRENT_TIMESTAMP -- 제거된 시간 + ); + ` + sqlStmt = fmt.Sprintf(sqlStmt, a.dbName) + + _, err = db.Exec(sqlStmt) + if err != nil { + return err + } + + sqlModifyTrigger := fmt.Sprintf(` + CREATE TRIGGER IF NOT EXISTS update_ModificationTime + AFTER UPDATE ON %s + FOR EACH ROW + BEGIN + UPDATE %s SET + updateAt = CURRENT_TIMESTAMP + WHERE id = NEW.id; + END; + `, a.dbName, a.dbName) + + _, err = db.Exec(sqlModifyTrigger) + if err != nil { + return err + } + + return nil +} + +/* +refer : https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa394378(v=vs.85) +class Win32_Product : CIM_Product + + { + uint16 AssignmentType; + string Caption; + string Description; + string IdentifyingNumber; + string InstallDate; + datetime InstallDate2; + string InstallLocation; + sint16 InstallState; + string HelpLink; + string HelpTelephone; + string InstallSource; + string Language; + string LocalPackage; + string Name; + string PackageCache; + string PackageCode; + string PackageName; + string ProductID; + string RegOwner; + string RegCompany; + string SKUNumber; + string Transforms; + string URLInfoAbout; + string URLUpdateInfo; + string Vendor; + uint32 WordCount; + string Version; + }; +*/ +type Win32_Product struct { + Name string // 제품 이름 + Version string // 제품 버전 + Language string // 제품의 언어 + Vendor string // 제품 공급자 + InstallDate2 string // 설치 날짜 + InstallLocation string // 패키지 설치 위치 + InstallSource string // 설치 소스 위치 + PackageName string // 원래 패키지 이름 + PackageCode string // 패키지 식별자 + RegCompany string // 제품을 사용하는 것으로 등록된 회사 이름 + RegOwner string // 제품을 사용하는 것으로 등록된 사용자 이름 + URLInfoAbout string // 제품에 대한 정보가 제공되는 URL + Description string // 제품 설명 +} + +func getApplicationList() []Win32_Product { + var dst []Win32_Product + query := "SELECT Name, AgentUUID, Version, Language, Vendor, InstallDate2, InstallLocation, InstallSource, PackageName, PackageCode, RegCompany, RegOwner, URLInfoAbout, Description FROM Win32_Product" + err := wmi.Query(query, &dst) + if err != nil { + log.Fatalf("wmi query failed: %v", err) + } + for i := range dst { + input := dst[i].PackageCode + if strings.HasPrefix(input, "{") && strings.HasSuffix(input, "}") { + input = strings.Replace(input, "{", "", 1) + input = strings.Replace(input, "}", "", 1) + } + dst[i].PackageCode = input + } + + return dst +} + +func (a *ApplicationDB) insertRecord(data DapplicationDB) error { + // ProductID 가 있는지 확인 후 중복되는 것이 없으면 insert 하기 + + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`INSERT INTO %s ( Name, Version, Language, Vendor, + InstallDate2, InstallLocation, InstallSource, PackageName, PackageCode, RegCompany, + RegOwner, URLInfoAbout, Description ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, a.dbName) + + stmt, err := db.Prepare(query) + defer stmt.Close() + if err != nil { + return err + } + + _, err = stmt.Exec(&data.Name, &data.Version, &data.Language, &data.Vendor, + &data.InstallDate2, &data.InstallLocation, &data.InstallSource, &data.PackageName, + &data.PackageCode, &data.RegCompany, &data.RegOwner, &data.URLInfoAbout, &data.Description) + + if err != nil { + return err + } + + return nil +} + +/* +selectRecords()를 통해 반환된 DsystemInfoDB 객체의 값을 수정한 후, +수정된 객체를 updateRecord 함수의 매개변수로 전달합시오 +*/ +func (a *ApplicationDB) updateByPackageCode(data *DapplicationDB) error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`UPDATE %s SET Name = ?, AgentUUID = ?, Version = ?, Language = ?, Vendor = ?, InstallDate2 = ?, InstallLocation = ?, InstallSource = ?, PackageName = ?, RegCompany = ?, RegOwner = ?, URLInfoAbout = ?, Description = ? WHERE PackageCode = ?`, a.dbName) + _, err = db.Exec(query, data.Name, data.AgentUUID, data.Version, data.Language, data.Vendor, data.InstallDate2, data.InstallLocation, data.InstallSource, data.PackageName, data.RegCompany, data.RegOwner, data.URLInfoAbout, data.Description, data.PackageCode) + if err != nil { + return err + } + + return nil +} + +func (s *ApplicationDB) selectByPackageCode(packageCode string) (*DapplicationDB, error) { + db, err := getDBPtr() + if err != nil { + return nil, err + } + defer db.Close() + + query := fmt.Sprintf(`SELECT * FROM %s WHERE PackageCode = '%s' LIMIT 1`, s.dbName, packageCode) + row, err := db.Query(query) + defer row.Close() + if err != nil { + return nil, err + } + + var data DapplicationDB + + if row.Next() == false { + return &DapplicationDB{PackageCode: "-1"}, nil + } + err = row.Scan(&data.ID, &data.Name, &data.AgentUUID, &data.Version, &data.Language, &data.Vendor, + &data.InstallDate2, &data.InstallLocation, &data.InstallSource, &data.PackageName, + &data.PackageCode, &data.RegCompany, &data.RegOwner, &data.URLInfoAbout, &data.Description, + &data.isDeleted, &data.CreateAt, &data.UpdateAt, &data.deletedAt) + if err != nil { + return nil, err + } + + return &data, nil +} + +func (s *ApplicationDB) deleteByPackageCode(packageCode string) error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`DELETE FROM %s WHERE PackageCode = ?`, s.dbName) + _, err = db.Exec(query, packageCode) + if err != nil { + return err + } + + return nil +} + +func (s *ApplicationDB) selectAllRecords() ([]DapplicationDB, error) { + db, err := getDBPtr() + if err != nil { + return nil, err + } + defer db.Close() + + query := fmt.Sprintf(`SELECT * FROM %s `, s.dbName) + row, err := db.Query(query) + if err != nil { + return nil, err + } + + var rows []DapplicationDB + + for row.Next() { + var data DapplicationDB + + err = row.Scan(&data.ID, &data.Name, &data.AgentUUID, &data.Version, &data.Language, &data.Vendor, + &data.InstallDate2, &data.InstallLocation, &data.InstallSource, &data.PackageName, + &data.PackageCode, &data.RegCompany, &data.RegOwner, &data.URLInfoAbout, &data.Description, + &data.isDeleted, &data.CreateAt, &data.UpdateAt, &data.deletedAt) + if err != nil { + return nil, err + } + rows = append(rows, data) + } + + return rows, nil +} diff --git a/Model/ApplicationDB_test.go b/Model/ApplicationDB_test.go new file mode 100644 index 0000000..c7eb07f --- /dev/null +++ b/Model/ApplicationDB_test.go @@ -0,0 +1,195 @@ +package Model + +import ( + "fmt" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestApplicationDB_createTable(t1 *testing.T) { + type fields struct { + dbName string + } + tests := []struct { + name string + fields fields + }{ + {name: "Test case 1"}, + } + + for _, tt := range tests { + t1.Run(tt.name, func(t *testing.T) { + appdb := NewApplicationDB() + err := appdb.createTable() + if err != nil { + t1.Fatalf("Error creating table: %v", err) + } + + // ========== 검증 ============= + dbPtr, err := getDBPtr() + if err != nil { + t1.Fatalf(appdb.dbName + " : DB 포인터를 가져올 수 없습니다. getDBPtr() 함수 오류\n" + err.Error()) + } + + query := fmt.Sprintf("select * from sqlite_master where name = '%s'", appdb.dbName) + + dsys := &sqlite_master{} + + rst := dbPtr.QueryRow(query).Scan(&dsys.Type, &dsys.name, &dsys.tbl_name, &dsys.rootpage, &dsys.sql) + if rst != nil { + t1.Fatalf(appdb.dbName + " : 생성된 테이블이 존재하지 않습니다.") + } + assert.Equal(t1, dsys.name, appdb.dbName) + }) + } +} + +func TestApplicationDB_CRUD(t1 *testing.T) { + type fields struct { + dbName string + } + tests := []struct { + name string + fields fields + }{ + {name: "Test case 1"}, + } + + for _, tt := range tests { + t1.Run(tt.name, func(t *testing.T) { + // ============ Create 테스트 ================ + appdb := NewApplicationDB() + appdb.createTable() + + wind32 := getApplicationList()[0] + data := DapplicationDB{} + data.Name = wind32.Name + data.Description = wind32.Description + data.Version = wind32.Version + data.Vendor = wind32.Vendor + data.InstallDate2 = wind32.InstallDate2 + data.InstallLocation = wind32.InstallLocation + data.InstallSource = wind32.InstallSource + data.Language = wind32.Language + data.PackageCode = wind32.PackageCode + data.PackageName = wind32.PackageName + data.RegCompany = wind32.RegCompany + data.RegOwner = wind32.RegOwner + data.URLInfoAbout = wind32.URLInfoAbout + + err := appdb.insertRecord(data) + if err != nil { + t.Fatalf(appdb.dbName + " : insert 에러\n" + err.Error()) + } + + // ========== Create 검증 ============= + dbPtr, err := getDBPtr() + if err != nil { + t.Fatalf(appdb.dbName + " : DB 포인터를 가져올 수 없습니다. getDBPtr() 함수 오류\n" + err.Error()) + } + + query := fmt.Sprintf("select * from %s", appdb.dbName) + data2 := &DapplicationDB{} + row := dbPtr.QueryRow(query) + if err != nil { + t.Fatalf(appdb.dbName + " : select Qeury 오류\n" + err.Error()) + } + + err = row.Scan(&data2.ID, &data2.Name, &data2.Version, &data2.Language, &data2.Vendor, + &data2.InstallDate2, &data2.InstallLocation, &data2.InstallSource, &data2.PackageName, + &data2.PackageCode, &data2.RegCompany, &data2.RegOwner, &data2.URLInfoAbout, &data2.Description, + &data2.isDeleted, &data2.CreateAt, &data2.UpdateAt, &data2.deletedAt) + + if err != nil { + t.Fatalf(appdb.dbName + " : DapplicationDB 내용이 실제 DB 컬럼 내용과 일치하지 않습니다.\n" + err.Error()) + } + + assert.Equal(t, data2.URLInfoAbout, data.URLInfoAbout) + assert.Equal(t, data2.Name, data.Name) + assert.Equal(t, data2.RegCompany, data.RegCompany) + assert.Equal(t, data2.RegOwner, data.RegOwner) + assert.Equal(t, data2.Language, data.Language) + assert.Equal(t, data2.InstallSource, data.InstallSource) + assert.Equal(t, data2.InstallDate2, data.InstallDate2) + assert.Equal(t, data2.Description, data.Description) + assert.Equal(t, data2.Version, data.Version) + + // ============ Read 테스트 ================ + data3, err := appdb.selectAllRecords() + data4 := data3[0] + if err != nil { + t1.Fatalf("select 테스트 에러\n" + err.Error()) + } + + assert.Equal(t, data2.URLInfoAbout, data4.URLInfoAbout) + assert.Equal(t, data2.Name, data4.Name) + assert.Equal(t, data2.RegCompany, data4.RegCompany) + assert.Equal(t, data2.RegOwner, data4.RegOwner) + assert.Equal(t, data2.Language, data4.Language) + assert.Equal(t, data2.InstallSource, data4.InstallSource) + assert.Equal(t, data2.InstallDate2, data4.InstallDate2) + assert.Equal(t, data2.Description, data4.Description) + assert.Equal(t, data2.Version, data4.Version) + + // ============ Delete 테스트 ================ + data6, err := appdb.selectByPackageCode(data.PackageCode) + if err != nil { + t1.Fatalf(": selectByPackageCode 실패\n" + err.Error()) + } + assert.NotEqual(t, data6.PackageCode, "-1") + + err = appdb.deleteByPackageCode(data.PackageCode) + if err != nil { + t1.Fatalf("삭제 실패\n" + err.Error()) + } + + data7, err := appdb.selectByPackageCode(data.PackageCode) + if err != nil { + t1.Fatalf(": selectByPackageCode 실패\n" + err.Error()) + } + assert.Equal(t, data7.PackageCode, "-1") + }) + } +} + +//func TestApplicationDB_CreateAll(t1 *testing.T) { +// type fields struct { +// dbName string +// } +// tests := []struct { +// name string +// fields fields +// }{ +// {name: "Test case 1"}, +// } +// for _, tt := range tests { +// t1.Run(tt.name, func(t *testing.T) { +// // ============ Create 테스트 ================ +// appdb := NewApplicationDB() +// appdb.createTable() +// +// wind32 := getApplicationList() +// for _, wind := range wind32 { +// data := DapplicationDB{} +// data.Name = wind.Name +// data.Description = wind.Description +// data.Version = wind.Version +// data.Vendor = wind.Vendor +// data.InstallDate2 = wind.InstallDate2 +// data.InstallLocation = wind.InstallLocation +// data.InstallSource = wind.InstallSource +// data.Language = wind.Language +// data.PackageCode = wind.PackageCode +// data.PackageName = wind.PackageName +// data.RegCompany = wind.RegCompany +// data.RegOwner = wind.RegOwner +// data.URLInfoAbout = wind.URLInfoAbout +// +// err := appdb.insertRecord(data) +// if err != nil { +// t.Fatalf(appdb.dbName + " : insert 에러\n" + err.Error()) +// } +// } +// }) +// } +//} diff --git a/Model/nosqldb.go b/Model/nosqldb.go new file mode 100644 index 0000000..94590e0 --- /dev/null +++ b/Model/nosqldb.go @@ -0,0 +1,42 @@ +package Model + +import ( + "context" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "log" + "time" +) + +/* +* +Mongodb는 100개의 커넥션 풀을 지원한다. +*/ +func getNoSqlDbPtr() { + clientOptions := options.Client().ApplyURI("mongodb://localhost:27017"). + SetMaxPoolSize(50). + SetMinPoolSize(10). + SetMaxConnIdleTime(30 * time.Second) + + client, err := mongo.NewClient(clientOptions) + if err != nil { + log.Fatal(err) + } + + // 연결 설정 + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + defer cancel() + + err = client.Connect(ctx) + if err != nil { + log.Fatal(err) + } + + defer func() { + if err := client.Disconnect(ctx); err != nil { + log.Fatal(err) + } + }() + + database := client.Database("") +} diff --git a/PacketQueue.go b/PacketQueue.go new file mode 100644 index 0000000..ae82798 --- /dev/null +++ b/PacketQueue.go @@ -0,0 +1,3 @@ +package main + +// 해당 코드는 Chatgpt 로 작성되었습니다. diff --git a/app.go b/app.go index 31dfb69..c35f285 100644 --- a/app.go +++ b/app.go @@ -1,27 +1,179 @@ package main import ( + "errors" + "fmt" + "github.com/HTTPs-omma/HSProtocol/HSProtocol" "github.com/gofiber/fiber/v3" "github.com/joho/godotenv" - "log" + "net" + "sync" ) +var queue *HSQueue // 패키지 수준에서 전역 큐 생성 + func main() { err := godotenv.Load() if err != nil { panic("Error loading .env file") } + queue = NewHSQueue() + + if err != nil { + panic("큐 생성 에러") + } + + // tcp + go TCPServer() + + // HTTP + //go HTTPServer() + + // udp + //go UDPServer() + + for { + if queue.HasNext() { + hs, err := queue.Dequeue() + if err != nil { + fmt.Errorf("queue.Dequeue() 에러 : ", err) + continue + } + fmt.Println("uuid : ", hs.UUID) + fmt.Println("command : ", hs.Command) + } + } + +} + +func TCPServer() { + listener, err := net.Listen("tcp", "localhost:8080") + if err != nil { + fmt.Println("Error starting TCP server:", err) + return + } + defer listener.Close() + + fmt.Println("TCP server listening on port 8080") + + for { + conn, err := listener.Accept() + if err != nil { + fmt.Println("Error accepting connection:", err) + continue + } + + go handleTCPConnection(conn) + } +} + +func handleTCPConnection(conn net.Conn) { + defer conn.Close() // 함수 호출 종료 후 Close + + buffer := make([]byte, 1024) + for { + n, err := conn.Read(buffer) + if err != nil { + fmt.Println("Error reading from connection:", err) + break + } + if n < 1 { + continue + } + + HSMgr := HSProtocol.NewHSProtocolManager() + hs, err := HSMgr.Parsing(buffer[:n]) + if err != nil { + fmt.Println("Error parsing:", err) + continue + } + // 받은 데이터를 PacketQueue에 추가 + err = queue.Enqueue(*hs) + + if err != nil { + fmt.Println("Error adding packet to queue:", err) + } else { + fmt.Printf("Received and queued packet: %x\n", buffer[:n]) + } + } +} - // Initialize a new Fiber app +// HTTP 서버 함수 (Fiber 사용) +func HTTPServer() { app := fiber.New() - // Define a route for the GET method on the root path '/' - app.Get("/", func(c fiber.Ctx) error { - // Send a string response to the client - return c.SendString("Hello, World 👋!") + app.Get("/status", func(c *fiber.Ctx) error { + + return c.SendString("문자") }) + app.Get("/next", queueNextHandler) + + fmt.Println("HTTP server listening on port 8081") + err := app.Listen(":80") + if err != nil { + fmt.Println("Error starting HTTP server:", err) + } +} + +const MaxQueueSize = 10000 // 큐의 최대 크기 + +// HS 타입을 위한 큐 구조체 정의 +type HSQueue struct { + items []HSProtocol.HS // HS 타입의 요소를 저장할 슬라이스 + lock sync.Mutex // 큐 접근 동기화를 위한 뮤텍스 + cond *sync.Cond // 큐의 상태를 확인하기 위한 조건 변수 +} + +// 새로운 HSQueue 생성 +func NewHSQueue() *HSQueue { + q := &HSQueue{ + items: make([]HSProtocol.HS, 0, MaxQueueSize), // 큐의 크기를 설정 + } + q.cond = sync.NewCond(&q.lock) // 조건 변수 초기화 + return q +} + +// 큐에 요소 추가 (Enqueue) +func (q *HSQueue) Enqueue(item HSProtocol.HS) error { + q.lock.Lock() + defer q.lock.Unlock() + + if len(q.items) >= MaxQueueSize { + return errors.New("queue is full") + } + + q.items = append(q.items, item) + q.cond.Signal() // 대기 중인 고루틴에 신호를 보냄 + return nil +} + +// 큐에 첫 번째 값이 있는지 확인 (HasNext) +func (q *HSQueue) HasNext() bool { + q.lock.Lock() + defer q.lock.Unlock() + + // 큐가 비어 있지 않으면 true 반환 + return len(q.items) > 0 +} + +// 큐에서 요소 제거 (Dequeue) +func (q *HSQueue) Dequeue() (HSProtocol.HS, error) { + q.lock.Lock() + defer q.lock.Unlock() + + for len(q.items) == 0 { + q.cond.Wait() // 큐가 비어있으면 대기 + } + + item := q.items[0] + q.items = q.items[1:] + return item, nil +} - // Start the server on port 3000 - log.Fatal(app.Listen(":3000")) +// 큐의 현재 크기 확인 +func (q *HSQueue) Size() int { + q.lock.Lock() + defer q.lock.Unlock() + return len(q.items) } diff --git a/go.mod b/go.mod index 3ef6576..5502392 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( ) require ( + github.com/HTTPs-omma/HSProtocol v1.0.2 // indirect github.com/andybalholm/brotli v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect @@ -16,10 +17,12 @@ require ( github.com/go-ole/go-ole v1.2.6 // indirect github.com/gofiber/fiber/v3 v3.0.0-beta.3 // indirect github.com/gofiber/utils/v2 v2.0.0-beta.6 // indirect + github.com/golang-queue/queue v0.2.0 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/joho/godotenv v1.5.1 // indirect + github.com/jpillora/backoff v1.0.0 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/go.sum b/go.sum index 11f3f48..e36dd57 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/HTTPs-omma/HSProtocol v1.0.2 h1:YV2MDAljka+Th3RsL649Bz2ZU+KUhLerS4GcI/z++9c= +github.com/HTTPs-omma/HSProtocol v1.0.2/go.mod h1:IvJQe3yhvo0qunuPoB499HuGBGE3QS0MWU8OYRuvAus= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -15,6 +17,8 @@ github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTY github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY= github.com/gofiber/utils/v2 v2.0.0-beta.6 h1:ED62bOmpRXdgviPlfTmf0Q+AXzhaTUAFtdWjgx+XkYI= github.com/gofiber/utils/v2 v2.0.0-beta.6/go.mod h1:3Kz8Px3jInKFvqxDzDeoSygwEOO+3uyubTmUa6PqY+0= +github.com/golang-queue/queue v0.2.0 h1:R0INU16rLCzYmc5h9wqHI/6owNxqcRVVMd5gyKVmnfU= +github.com/golang-queue/queue v0.2.0/go.mod h1:5nEkJTzw9Boc8ZCylQlrJK5f/Vd8Uo58yAssRli5ckg= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -24,6 +28,8 @@ github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyf github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= From b1aa607ef92a0a637133ff56a200b04106b5d6db Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Sat, 31 Aug 2024 21:51:41 +0900 Subject: [PATCH 02/26] =?UTF-8?q?HTTPS-53=20<=20TCP=20=ED=86=B5=EC=8B=A0?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=9A=A9=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app.go | 121 +++++++++++++-------------------------------------------- 1 file changed, 27 insertions(+), 94 deletions(-) diff --git a/app.go b/app.go index c35f285..4430a55 100644 --- a/app.go +++ b/app.go @@ -1,23 +1,21 @@ package main import ( - "errors" + "bytes" "fmt" "github.com/HTTPs-omma/HSProtocol/HSProtocol" "github.com/gofiber/fiber/v3" "github.com/joho/godotenv" "net" - "sync" ) -var queue *HSQueue // 패키지 수준에서 전역 큐 생성 +var testCommand string = "dir /" func main() { err := godotenv.Load() if err != nil { panic("Error loading .env file") } - queue = NewHSQueue() if err != nil { panic("큐 생성 에러") @@ -26,23 +24,11 @@ func main() { // tcp go TCPServer() - // HTTP - //go HTTPServer() - // udp - //go UDPServer() + ////go UDPServer() - for { - if queue.HasNext() { - hs, err := queue.Dequeue() - if err != nil { - fmt.Errorf("queue.Dequeue() 에러 : ", err) - continue - } - fmt.Println("uuid : ", hs.UUID) - fmt.Println("command : ", hs.Command) - } - } + // HTTP + HTTPServer() } @@ -65,12 +51,13 @@ func TCPServer() { go handleTCPConnection(conn) } + } func handleTCPConnection(conn net.Conn) { defer conn.Close() // 함수 호출 종료 후 Close - buffer := make([]byte, 1024) + buffer := make([]byte, 1024*1024) for { n, err := conn.Read(buffer) if err != nil { @@ -82,19 +69,21 @@ func handleTCPConnection(conn net.Conn) { } HSMgr := HSProtocol.NewHSProtocolManager() - hs, err := HSMgr.Parsing(buffer[:n]) + hs, err := HSMgr.Parsing(buffer) if err != nil { fmt.Println("Error parsing:", err) continue } - // 받은 데이터를 PacketQueue에 추가 - err = queue.Enqueue(*hs) - if err != nil { - fmt.Println("Error adding packet to queue:", err) - } else { - fmt.Printf("Received and queued packet: %x\n", buffer[:n]) + if hs.Command == 0b0000000110 { // payload 를 받아옴 + conn.Write([]byte(testCommand)) + } + + if hs.Command == 0b0000000111 { // 실행 결과를 작성함. + msg := bytes.ReplaceAll(hs.Data, []byte{0x00}, []byte{}) + fmt.Println("Log : ", string(msg)) } + } } @@ -102,78 +91,22 @@ func handleTCPConnection(conn net.Conn) { func HTTPServer() { app := fiber.New() - app.Get("/status", func(c *fiber.Ctx) error { + app.Post("/getPacket", func(ctx fiber.Ctx) error { + req := ctx.Body() + HSMgr := HSProtocol.NewHSProtocolManager() + hs, err := HSMgr.Parsing(req) + if err != nil { + return fmt.Errorf("Error parsing:", err) + } + + fmt.Println("hs.uuid : ", hs.UUID) - return c.SendString("문자") + return nil }) - app.Get("/next", queueNextHandler) - fmt.Println("HTTP server listening on port 8081") + fmt.Println("HTTP server listening on port 80") err := app.Listen(":80") if err != nil { fmt.Println("Error starting HTTP server:", err) } } - -const MaxQueueSize = 10000 // 큐의 최대 크기 - -// HS 타입을 위한 큐 구조체 정의 -type HSQueue struct { - items []HSProtocol.HS // HS 타입의 요소를 저장할 슬라이스 - lock sync.Mutex // 큐 접근 동기화를 위한 뮤텍스 - cond *sync.Cond // 큐의 상태를 확인하기 위한 조건 변수 -} - -// 새로운 HSQueue 생성 -func NewHSQueue() *HSQueue { - q := &HSQueue{ - items: make([]HSProtocol.HS, 0, MaxQueueSize), // 큐의 크기를 설정 - } - q.cond = sync.NewCond(&q.lock) // 조건 변수 초기화 - return q -} - -// 큐에 요소 추가 (Enqueue) -func (q *HSQueue) Enqueue(item HSProtocol.HS) error { - q.lock.Lock() - defer q.lock.Unlock() - - if len(q.items) >= MaxQueueSize { - return errors.New("queue is full") - } - - q.items = append(q.items, item) - q.cond.Signal() // 대기 중인 고루틴에 신호를 보냄 - return nil -} - -// 큐에 첫 번째 값이 있는지 확인 (HasNext) -func (q *HSQueue) HasNext() bool { - q.lock.Lock() - defer q.lock.Unlock() - - // 큐가 비어 있지 않으면 true 반환 - return len(q.items) > 0 -} - -// 큐에서 요소 제거 (Dequeue) -func (q *HSQueue) Dequeue() (HSProtocol.HS, error) { - q.lock.Lock() - defer q.lock.Unlock() - - for len(q.items) == 0 { - q.cond.Wait() // 큐가 비어있으면 대기 - } - - item := q.items[0] - q.items = q.items[1:] - return item, nil -} - -// 큐의 현재 크기 확인 -func (q *HSQueue) Size() int { - q.lock.Lock() - defer q.lock.Unlock() - - return len(q.items) -} From 14943d650879a011a1a733987a7912ec09eb7c71 Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Mon, 2 Sep 2024 22:43:32 +0900 Subject: [PATCH 03/26] =?UTF-8?q?HTTPS-53=20<=20CommandDispatcher=20:=20up?= =?UTF-8?q?dateHealth=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/CommandDispatcher.go | 187 ++++++++++++++++++++++++++++++++++++++ Model/AgentStatus.go | 77 ++++++++++++---- 2 files changed, 245 insertions(+), 19 deletions(-) create mode 100644 Core/CommandDispatcher.go diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go new file mode 100644 index 0000000..9dcafb0 --- /dev/null +++ b/Core/CommandDispatcher.go @@ -0,0 +1,187 @@ +package Core + +import ( + "fmt" + "github.com/HTTPs-omma/HSProtocol/HSProtocol" + "github.com/your/repo/Model" +) +// https://github.com/HTTPs-omma/HSProtocol + +type CommandDispatcher struct { + +} + + +func (cd *CommandDispatcher)action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { + //hsMgr := HSProtocol.NewHSProtocolManager() + + switch hs.Command { + case 0b0000000001 : + return updateHealth(hs) + case 0b0000000010 : + updateProtocol(hs) + case 0b0000000011 : + postSystemInfo(hs) + case 0b0000000100 : + break; // 예약 + case 0b0000000101 : + postApplicationInfo(hs) + case 0b0000000110 : + getProcedure(hs) + case 0b0000000111 : + postLogOfProcedure(hs) + } + + return nil, fmt.Errorf("Invalid Command") +} + +// Command: 1 (0b0000000001) +func updateHealth(hs *HSProtocol.HS)(*HSProtocol.HS, error){ + agsmd := Model.NewAgentStatusDB() + rst, err := agsmd.ExistRecord() + if err != nil { + return nil, err + } + if( rst ) { + return nil, fmt.Errorf("Agent Status DB : no Records") + } + + + + records, err := agsmd.SelectRecords() + if err != nil { + return nil, err + } + + hs_uuid := string(hs.UUID[:]) + + + flag := false + for _, record := range records { + if record.UUID == hs_uuid { + flag = true + } + } + + if flag == true { + agsmd.UpdateRecord(&Model.AgentStatusRecord{ + UUID : string(hs.UUID[:]), + Status: Model.BinaryToAgentStatus(hs.HealthStatus), + }) + return &HSProtocol.HS{ // ACK + Version: hs.Version, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + }, nil + } else if (flag == false) && ( hs.HealthStatus == uint8(Model.Waiting) ) { + agsmd.InsertRecord(&Model.AgentStatusRecord{ + UUID : string(hs.UUID[:]), + Status: Model.BinaryToAgentStatus(hs.HealthStatus), + }) + + return &HSProtocol.HS{ // ACK + Version: hs.Version, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + }, nil + } + + + return nil, fmt.Errorf("incorrect AgentStatusRecords") +} + +// Command: 2 (0b0000000010) +func updateProtocol(hs *HSProtocol.HS)(*HSProtocol.HS, error){ + + + + return &HSProtocol.HS{ // ACK + Version: hs.Version, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + }, nil +} + + +// Command: 3 (0b0000000011) +func postSystemInfo (hs *HSProtocol.HS)(*HSProtocol.HS, error){ + + + + + return &HSProtocol.HS{ // ACK + Version: hs.Version, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + }, nil +} + + +// Command: 5 (0b0000000101) +func postApplicationInfo (hs *HSProtocol.HS)(*HSProtocol.HS, error){ + + + + + return &HSProtocol.HS{ // ACK + Version: hs.Version, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + }, nil +} + +// Command: 5 (0b0000000110) +func getProcedure (hs *HSProtocol.HS)(*HSProtocol.HS, error){ + + + + + return &HSProtocol.HS{ // ACK + Version: hs.Version, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + }, nil +} + +// Command: 5 (0b0000000110) +func postLogOfProcedure (hs *HSProtocol.HS)(*HSProtocol.HS, error){ + + + + + return &HSProtocol.HS{ // ACK + Version: hs.Version, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + }, nil +} + + diff --git a/Model/AgentStatus.go b/Model/AgentStatus.go index 2b8914b..c02ea41 100644 --- a/Model/AgentStatus.go +++ b/Model/AgentStatus.go @@ -5,25 +5,44 @@ import ( "time" ) -/* -agent 의 상태 Status 는 총 3가지로 나뉜다. +// Protocol 유형을 정의합니다. +type Protocol uint8 -Running : 동작중인 상태 -waiting : 대기중인 상태 -Stopping : 정지후 사라지기 전에 상태 -*/ +const ( + TCP Protocol = 0b0001 // TCP 프로토콜 + UDP Protocol = 0b0010 // UDP 프로토콜 + HTTP Protocol = 0b0011 // HTTP 프로토콜 + HTTPS Protocol = 0b0100 // HTTPS 프로토콜 + UnknownProtocol Protocol = 0b0000 // 알 수 없는 프로토콜 +) + +// Protocol을 문자열로 변환하는 메서드를 구현합니다. +func (p Protocol) String() string { + switch p { + case TCP: + return "TCP" + case UDP: + return "UDP" + case HTTP: + return "HTTP" + case HTTPS: + return "HTTPS" + default: + return "Unknown" + } +} + +// AgentStatus 유형을 정의합니다. type AgentStatus int const ( - Running AgentStatus = iota // 동작 중인 상태 - Waiting // 대기 중인 상태 + Waiting AgentStatus = iota // 동작 중인 상태 + Running // 대기 중인 상태 Stopping // 정지 후 사라지기 전의 상태 + Deleted + Unknown ) -/* -해당 코드를 빠른 코드 작성을 위해서 Chatgpt 가 작성후 허남정 연구원이 검토하는 형태로 만들었습니다. -*/ - // AgentStatus를 문자열로 변환하는 메서드를 구현합니다. func (s AgentStatus) String() string { switch s { @@ -33,11 +52,29 @@ func (s AgentStatus) String() string { return "Waiting" case Stopping: return "Stopping" + case Deleted: + return "Deleted" default: return "Unknown" } } +// Binary 값을 AgentStatus로 변환하는 메서드를 구현합니다. +func BinaryToAgentStatus(i uint8) AgentStatus { + switch i { + case 0b00: + return Waiting + case 0b01: + return Running + case 0b10: + return Stopping + case 0b11: + return Deleted + default: + return Unknown + } +} + type AgentStatusDB struct { dbName string } @@ -46,6 +83,7 @@ type AgentStatusRecord struct { ID int UUID string Status AgentStatus + Protocol Protocol CreatedAt time.Time UpdatedAt time.Time } @@ -68,6 +106,7 @@ func (s *AgentStatusDB) CreateTable() error { id INTEGER PRIMARY KEY AUTOINCREMENT, uuid TEXT NOT NULL UNIQUE, status int, + protocol int Default 0, createAt DATETIME DEFAULT CURRENT_TIMESTAMP, updateAt DATETIME DEFAULT CURRENT_TIMESTAMP ); @@ -107,14 +146,14 @@ func (s *AgentStatusDB) InsertRecord(data *AgentStatusRecord) error { } defer db.Close() - query := fmt.Sprintf(`INSERT INTO %s (uuid, status) VALUES (?, ?)`, s.dbName) + query := fmt.Sprintf(`INSERT INTO %s (uuid, status, protocol) VALUES (?, ?, ?)`, s.dbName) stmt, err := db.Prepare(query) if err != nil { return err } defer stmt.Close() - _, err = stmt.Exec(data.UUID, data.Status) + _, err = stmt.Exec(data.UUID, data.Status, data.Protocol) if err != nil { return err } @@ -130,7 +169,7 @@ func (s *AgentStatusDB) SelectRecords() ([]AgentStatusRecord, error) { } defer db.Close() - query := fmt.Sprintf(`SELECT id, uuid, status, createAt, updateAt FROM %s`, s.dbName) + query := fmt.Sprintf(`SELECT id, uuid, status, protocol, createAt, updateAt FROM %s`, s.dbName) rows, err := db.Query(query) if err != nil { return nil, err @@ -140,7 +179,7 @@ func (s *AgentStatusDB) SelectRecords() ([]AgentStatusRecord, error) { var records []AgentStatusRecord for rows.Next() { var record AgentStatusRecord - err := rows.Scan(&record.ID, &record.UUID, &record.Status, &record.CreatedAt, &record.UpdatedAt) + err := rows.Scan(&record.ID, &record.UUID, &record.Status, &record.Protocol, &record.CreatedAt, &record.UpdatedAt) if err != nil { return nil, err } @@ -150,7 +189,7 @@ func (s *AgentStatusDB) SelectRecords() ([]AgentStatusRecord, error) { return records, nil } -// UpdateRecord updates the status of a record identified by its UUID. +// UpdateRecord updates the status and protocol of a record identified by its UUID. func (s *AgentStatusDB) UpdateRecord(data *AgentStatusRecord) error { db, err := getDBPtr() if err != nil { @@ -158,8 +197,8 @@ func (s *AgentStatusDB) UpdateRecord(data *AgentStatusRecord) error { } defer db.Close() - query := fmt.Sprintf(`UPDATE %s SET status = ? WHERE uuid = ?`, s.dbName) - _, err = db.Exec(query, data.Status, data.UUID) + query := fmt.Sprintf(`UPDATE %s SET status = ?, protocol = ? WHERE uuid = ?`, s.dbName) + _, err = db.Exec(query, data.Status, data.Protocol, data.UUID) if err != nil { return err } From a14219bf3a01be0e5b2eaadc75a8485e3452e14d Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Tue, 3 Sep 2024 16:08:42 +0900 Subject: [PATCH 04/26] =?UTF-8?q?=20updateProtocol=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/CommandDispatcher.go | 42 ++++++++++++++++++++++++------- Model/AgentStatus.go | 17 +++++++++++++ go.mod | 29 ++++++--------------- go.sum | 53 +++++++-------------------------------- 4 files changed, 66 insertions(+), 75 deletions(-) diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index 9dcafb0..fa859ae 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -69,7 +69,7 @@ func updateHealth(hs *HSProtocol.HS)(*HSProtocol.HS, error){ Status: Model.BinaryToAgentStatus(hs.HealthStatus), }) return &HSProtocol.HS{ // ACK - Version: hs.Version, + ProtocolID: hs.ProtocolID, Command: 0b0000000000, UUID: hs.UUID, HealthStatus: hs.HealthStatus, @@ -84,7 +84,7 @@ func updateHealth(hs *HSProtocol.HS)(*HSProtocol.HS, error){ }) return &HSProtocol.HS{ // ACK - Version: hs.Version, + ProtocolID : hs.ProtocolID, Command: 0b0000000000, UUID: hs.UUID, HealthStatus: hs.HealthStatus, @@ -101,10 +101,36 @@ func updateHealth(hs *HSProtocol.HS)(*HSProtocol.HS, error){ // Command: 2 (0b0000000010) func updateProtocol(hs *HSProtocol.HS)(*HSProtocol.HS, error){ + // protocolID := binary.BigEndian.Uint32(hs.Data) + agsmd := Model.NewAgentStatusDB() + rst, err := agsmd.ExistRecord() + if err != nil { + return nil, err + } + if( rst ) { + return nil, fmt.Errorf("Agent Status DB : no Records") + } + + + records, err := agsmd.SelectRecords() + if err != nil { + return nil, err + } + hs_uuid := string(hs.UUID[:]) + + for _, record := range records { + if record.UUID == hs_uuid { + record.Protocol = Model.BinaryToProtocol( hs.ProtocolID ) + err = agsmd.UpdateRecord(&record) + if err != nil { + return nil, err + } + } + } return &HSProtocol.HS{ // ACK - Version: hs.Version, + ProtocolID: hs.ProtocolID, Command: 0b0000000000, UUID: hs.UUID, HealthStatus: hs.HealthStatus, @@ -119,10 +145,8 @@ func updateProtocol(hs *HSProtocol.HS)(*HSProtocol.HS, error){ func postSystemInfo (hs *HSProtocol.HS)(*HSProtocol.HS, error){ - - return &HSProtocol.HS{ // ACK - Version: hs.Version, + ProtocolID: hs.ProtocolID, Command: 0b0000000000, UUID: hs.UUID, HealthStatus: hs.HealthStatus, @@ -140,7 +164,7 @@ func postApplicationInfo (hs *HSProtocol.HS)(*HSProtocol.HS, error){ return &HSProtocol.HS{ // ACK - Version: hs.Version, + ProtocolID: hs.ProtocolID, Command: 0b0000000000, UUID: hs.UUID, HealthStatus: hs.HealthStatus, @@ -157,7 +181,7 @@ func getProcedure (hs *HSProtocol.HS)(*HSProtocol.HS, error){ return &HSProtocol.HS{ // ACK - Version: hs.Version, + ProtocolID: hs.ProtocolID, Command: 0b0000000000, UUID: hs.UUID, HealthStatus: hs.HealthStatus, @@ -174,7 +198,7 @@ func postLogOfProcedure (hs *HSProtocol.HS)(*HSProtocol.HS, error){ return &HSProtocol.HS{ // ACK - Version: hs.Version, + ProtocolID : hs.ProtocolID, Command: 0b0000000000, UUID: hs.UUID, HealthStatus: hs.HealthStatus, diff --git a/Model/AgentStatus.go b/Model/AgentStatus.go index c02ea41..e633bb9 100644 --- a/Model/AgentStatus.go +++ b/Model/AgentStatus.go @@ -75,6 +75,23 @@ func BinaryToAgentStatus(i uint8) AgentStatus { } } +// Binary 값을 AgentStatus로 변환하는 메서드를 구현합니다. +func BinaryToProtocol(i uint8) Protocol { + switch i { + case 0b0001: + return TCP + case 0b0010: + return UDP + case 0b0011: + return HTTP + case 0b0100: + return HTTPS + default: + return UnknownProtocol + } +} + + type AgentStatusDB struct { dbName string } diff --git a/go.mod b/go.mod index 5502392..570ba99 100644 --- a/go.mod +++ b/go.mod @@ -3,35 +3,28 @@ module github.com/your/repo go 1.23.0 require ( + github.com/HTTPs-omma/HSProtocol v1.0.3 + github.com/gofiber/fiber/v3 v3.0.0-beta.3 + github.com/joho/godotenv v1.5.1 github.com/stretchr/testify v1.9.0 github.com/yusufpapurcu/wmi v1.2.4 + go.mongodb.org/mongo-driver v1.16.1 ) require ( - github.com/HTTPs-omma/HSProtocol v1.0.2 // indirect github.com/andybalholm/brotli v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/elastic/go-sysinfo v1.14.1 // indirect - github.com/elastic/go-windows v1.0.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/gofiber/fiber/v3 v3.0.0-beta.3 // indirect github.com/gofiber/utils/v2 v2.0.0-beta.6 // indirect - github.com/golang-queue/queue v0.2.0 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect - github.com/joho/godotenv v1.5.1 // indirect - github.com/jpillora/backoff v1.0.0 // indirect github.com/klauspost/compress v1.17.9 // indirect + github.com/kr/pretty v0.1.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/montanaflynn/stats v0.7.1 // indirect - github.com/ncruces/go-strftime v0.1.9 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.55.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect @@ -39,18 +32,10 @@ require ( github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect - go.mongodb.org/mongo-driver v1.16.1 // indirect golang.org/x/crypto v0.24.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.24.0 // indirect golang.org/x/text v0.16.0 // indirect + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect - modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect - modernc.org/libc v1.55.3 // indirect - modernc.org/mathutil v1.6.0 // indirect - modernc.org/memory v1.8.0 // indirect - modernc.org/sqlite v1.32.0 // indirect - modernc.org/strutil v1.2.0 // indirect - modernc.org/token v1.1.0 // indirect ) diff --git a/go.sum b/go.sum index e36dd57..c4744a3 100644 --- a/go.sum +++ b/go.sum @@ -1,40 +1,34 @@ github.com/HTTPs-omma/HSProtocol v1.0.2 h1:YV2MDAljka+Th3RsL649Bz2ZU+KUhLerS4GcI/z++9c= github.com/HTTPs-omma/HSProtocol v1.0.2/go.mod h1:IvJQe3yhvo0qunuPoB499HuGBGE3QS0MWU8OYRuvAus= +github.com/HTTPs-omma/HSProtocol v1.0.3 h1:8OZxA4Vc2H1QsTLPYQ8B7++B5r0M8g6Gaom/IZ2JHvg= +github.com/HTTPs-omma/HSProtocol v1.0.3/go.mod h1:IvJQe3yhvo0qunuPoB499HuGBGE3QS0MWU8OYRuvAus= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/elastic/go-sysinfo v1.14.1 h1:BpY/Utfz75oKSpsQnbAJmmlnT3gBV9WFsopBEYgjhZY= -github.com/elastic/go-sysinfo v1.14.1/go.mod h1:FKUXnZWhnYI0ueO7jhsGV3uQJ5hiz8OqM5b3oGyaRr8= -github.com/elastic/go-windows v1.0.0 h1:qLURgZFkkrYyTTkvYpsZIgf83AUsdIHfvlJaqaZ7aSY= -github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg= github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY= github.com/gofiber/utils/v2 v2.0.0-beta.6 h1:ED62bOmpRXdgviPlfTmf0Q+AXzhaTUAFtdWjgx+XkYI= github.com/gofiber/utils/v2 v2.0.0-beta.6/go.mod h1:3Kz8Px3jInKFvqxDzDeoSygwEOO+3uyubTmUa6PqY+0= -github.com/golang-queue/queue v0.2.0 h1:R0INU16rLCzYmc5h9wqHI/6owNxqcRVVMd5gyKVmnfU= -github.com/golang-queue/queue v0.2.0/go.mod h1:5nEkJTzw9Boc8ZCylQlrJK5f/Vd8Uo58yAssRli5ckg= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -42,19 +36,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= -github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= -github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -89,7 +72,6 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -111,25 +93,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -howett.net/plist v0.0.0-20181124034731-591f970eefbb h1:jhnBjNi9UFpfpl8YZhA9CrOqpnJdvzuiHsl/dnxl11M= -howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= -modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= -modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= -modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U= -modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w= -modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= -modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= -modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= -modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s= -modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= -modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= -modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= -modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= From 2887dd88ac05c66357b07f6a8751ca769d156c21 Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Wed, 4 Sep 2024 23:31:53 +0900 Subject: [PATCH 05/26] =?UTF-8?q?HTTPS-53=20<=20updateProtocol=20=20=20=20?= =?UTF-8?q?=20=20=20=20=20=20=20=20postSystemInfo=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20=20=20postApplicationInfo=20=20=20=20=20=20=20=20=20=20?= =?UTF-8?q?=20=20getProcedure=20=20=20=20=20=20=20=20=20=20=20=20postLogOf?= =?UTF-8?q?Procedure=20=EB=93=B1=20=EA=B5=AC=ED=98=84=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/CommandDispatcher.go | 54 +++++++++++++++++------ Model/ApplicationDB.go | 26 ++++++++--- Model/FileMetaDB.go | 91 --------------------------------------- Model/SystemInfoDB.go | 62 ++++++++++++++++---------- Model/nosqldb.go | 42 +++++++++++------- 5 files changed, 128 insertions(+), 147 deletions(-) delete mode 100644 Model/FileMetaDB.go diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index fa859ae..cdb0c1d 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -6,12 +6,14 @@ import ( "github.com/your/repo/Model" ) // https://github.com/HTTPs-omma/HSProtocol - type CommandDispatcher struct { } + + + func (cd *CommandDispatcher)action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { //hsMgr := HSProtocol.NewHSProtocolManager() @@ -19,17 +21,17 @@ func (cd *CommandDispatcher)action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { case 0b0000000001 : return updateHealth(hs) case 0b0000000010 : - updateProtocol(hs) + return updateProtocol(hs) case 0b0000000011 : - postSystemInfo(hs) + return postSystemInfo(hs) case 0b0000000100 : break; // 예약 case 0b0000000101 : - postApplicationInfo(hs) + return postApplicationInfo(hs) case 0b0000000110 : - getProcedure(hs) + return getProcedure(hs) case 0b0000000111 : - postLogOfProcedure(hs) + return postLogOfProcedure(hs) } return nil, fmt.Errorf("Invalid Command") @@ -145,6 +147,17 @@ func updateProtocol(hs *HSProtocol.HS)(*HSProtocol.HS, error){ func postSystemInfo (hs *HSProtocol.HS)(*HSProtocol.HS, error){ + sysDB := Model.NewSystemInfoDB() + Dsys, err := sysDB.Unmarshal(hs.Data) + if err != nil { + return nil, err + } + + err = sysDB.InsertRecord(Dsys) + if err != nil { + return nil, err + } + return &HSProtocol.HS{ // ACK ProtocolID: hs.ProtocolID, Command: 0b0000000000, @@ -160,8 +173,15 @@ func postSystemInfo (hs *HSProtocol.HS)(*HSProtocol.HS, error){ // Command: 5 (0b0000000101) func postApplicationInfo (hs *HSProtocol.HS)(*HSProtocol.HS, error){ - - + appDB := Model.ApplicationDB{} + Dapp, err := appDB.Unmarshal(hs.Data) + if err != nil { + return nil, err + } + err = appDB.InsertRecord( Dapp ) + if err != nil { + return nil, err + } return &HSProtocol.HS{ // ACK ProtocolID: hs.ProtocolID, @@ -174,11 +194,20 @@ func postApplicationInfo (hs *HSProtocol.HS)(*HSProtocol.HS, error){ }, nil } -// Command: 5 (0b0000000110) -func getProcedure (hs *HSProtocol.HS)(*HSProtocol.HS, error){ +// Command: 6 (0b0000000110) +func getProcedure (hs *HSProtocol.HS)(*HSProtocol.HS, error){ + appDB := Model.ApplicationDB{} + Dapp, err := appDB.Unmarshal(hs.Data) + if err != nil { + return nil, err + } + err = appDB.InsertRecord( Dapp ) + if err != nil { + return nil, err + } return &HSProtocol.HS{ // ACK ProtocolID: hs.ProtocolID, @@ -191,11 +220,10 @@ func getProcedure (hs *HSProtocol.HS)(*HSProtocol.HS, error){ }, nil } -// Command: 5 (0b0000000110) +// Command: 7 (0b0000000111) func postLogOfProcedure (hs *HSProtocol.HS)(*HSProtocol.HS, error){ - - + Model. return &HSProtocol.HS{ // ACK ProtocolID : hs.ProtocolID, diff --git a/Model/ApplicationDB.go b/Model/ApplicationDB.go index 9e946ba..868fca6 100644 --- a/Model/ApplicationDB.go +++ b/Model/ApplicationDB.go @@ -1,6 +1,7 @@ package Model import ( + "encoding/json" "fmt" "github.com/yusufpapurcu/wmi" "log" @@ -145,7 +146,7 @@ type Win32_Product struct { Description string // 제품 설명 } -func getApplicationList() []Win32_Product { +func GetApplicationList() []Win32_Product { var dst []Win32_Product query := "SELECT Name, AgentUUID, Version, Language, Vendor, InstallDate2, InstallLocation, InstallSource, PackageName, PackageCode, RegCompany, RegOwner, URLInfoAbout, Description FROM Win32_Product" err := wmi.Query(query, &dst) @@ -164,7 +165,7 @@ func getApplicationList() []Win32_Product { return dst } -func (a *ApplicationDB) insertRecord(data DapplicationDB) error { +func (a *ApplicationDB) InsertRecord(data *DapplicationDB) error { // ProductID 가 있는지 확인 후 중복되는 것이 없으면 insert 하기 db, err := getDBPtr() @@ -198,7 +199,7 @@ func (a *ApplicationDB) insertRecord(data DapplicationDB) error { selectRecords()를 통해 반환된 DsystemInfoDB 객체의 값을 수정한 후, 수정된 객체를 updateRecord 함수의 매개변수로 전달합시오 */ -func (a *ApplicationDB) updateByPackageCode(data *DapplicationDB) error { +func (a *ApplicationDB) UpdateByPackageCode(data *DapplicationDB) error { db, err := getDBPtr() if err != nil { return err @@ -214,7 +215,7 @@ func (a *ApplicationDB) updateByPackageCode(data *DapplicationDB) error { return nil } -func (s *ApplicationDB) selectByPackageCode(packageCode string) (*DapplicationDB, error) { +func (s *ApplicationDB) SelectByPackageCode(packageCode string) (*DapplicationDB, error) { db, err := getDBPtr() if err != nil { return nil, err @@ -237,6 +238,7 @@ func (s *ApplicationDB) selectByPackageCode(packageCode string) (*DapplicationDB &data.InstallDate2, &data.InstallLocation, &data.InstallSource, &data.PackageName, &data.PackageCode, &data.RegCompany, &data.RegOwner, &data.URLInfoAbout, &data.Description, &data.isDeleted, &data.CreateAt, &data.UpdateAt, &data.deletedAt) + if err != nil { return nil, err } @@ -244,7 +246,7 @@ func (s *ApplicationDB) selectByPackageCode(packageCode string) (*DapplicationDB return &data, nil } -func (s *ApplicationDB) deleteByPackageCode(packageCode string) error { +func (s *ApplicationDB) DeleteByPackageCode(packageCode string) error { db, err := getDBPtr() if err != nil { return err @@ -260,7 +262,7 @@ func (s *ApplicationDB) deleteByPackageCode(packageCode string) error { return nil } -func (s *ApplicationDB) selectAllRecords() ([]DapplicationDB, error) { +func (s *ApplicationDB) SelectAllRecords() ([]DapplicationDB, error) { db, err := getDBPtr() if err != nil { return nil, err @@ -290,3 +292,15 @@ func (s *ApplicationDB) selectAllRecords() ([]DapplicationDB, error) { return rows, nil } + +func (s *ApplicationDB) Unmarshal(data []byte) (*DapplicationDB, error) { + + var Dapp DapplicationDB + err := json.Unmarshal(data, &Dapp) + if err != nil { + fmt.Println("Error unmarshaling JSON:", err) + return nil, err + } + + return &Dapp, nil +} diff --git a/Model/FileMetaDB.go b/Model/FileMetaDB.go deleted file mode 100644 index 537f47c..0000000 --- a/Model/FileMetaDB.go +++ /dev/null @@ -1,91 +0,0 @@ -package Model - -// -//import ( -// "log" -//) -// -//import ( -// _ "github.com/mattn/go-sqlite3" -//) -// -//type FileMetaDB struct { -// dbPath string -//} -// -//func NewFileMetaDB() (metaTable *FileMetaDB) { -// -// metaTable = &FileMetaDB{ -// dbPath: "file:db.db?cache=shared", -// } -// -// metaTable.createTable() -// -// return metaTable -//} -// -///* -//refer : https://github.com/steffenfritz/FileTrove?tab=readme-ov-file -//action : 인덱싱을 위한 데이터 테이블을 생성합니다. -//- 인덱싱 테이블을 만들 때, -// -//단일 바이너리 애플리케이션이 디렉터리 트리를 탐색하고 Siegfried를 사용하여 모든 일반 파일을 형식별로 식별합니다. -//이때 다음 정보를 제공합니다 : -//1. MIME type -//- 파일의 인터넷 미디어 타입을 나타내며, 파일의 형식을 식별합니다. -//- ex. 이미지 파일은 image/jpeg, -//2. PRONOM identifier -//3. Format version -//4. Identification proof and note -//5. filename extension -// -//os.Stat() is giving you the -//6. File size -//7. File creation time -//8. File modification time -//9. File access time -// -//and the same for directories -//Furthermore it creates and calculates -// -//10. UUIDv4s as unique identifiers (not stable across sessions) -//11. hash sums (md5, sha1, sha256, sha512 and blake2b-512) -//12. the entropy of each file (up to 1GB) -//13. and it extracts some EXIF metadata and -//14. you can add your own DublinCore Elements metadata to scans. -//15. A very powerful feature is FileTrove's ability to consume YARA-X rule files. -//16. FileTrove also checks if the file is in the NSRL. -//*/ -//func (t *FileMetaDB) createTable() { -// sqlStmt := ` -// CREATE TABLE IF NOT EXISTS FileMetadata ( -// id INTEGER PRIMARY KEY AUTOINCREMENT, -- 내부 ID, 자동 증가 -// uuid TEXT NOT NULL unique, -- UUIDv4 -// path TEXT NOT NULL, -- 파일 경로 -// name TEXT NOT NULL, -- 파일명 -// type TEXT NOT NULL, -- 파일 유형 (파일 또는 디렉터리) -// mime_type TEXT, -- MIME 타입 -// pronom_id TEXT, -- PRONOM 식별자 -// format_version TEXT, -- 포맷 버전 -// identification_proof TEXT, -- 식별 증거 및 노트 -// file_extension TEXT, -- 파일 확장자 -// file_size INTEGER, -- 파일 크기 (바이트) -// creation_time DATETIME, -- 파일 생성 시간 -// modification_time DATETIME, -- 파일 수정 시간 -// access_time DATETIME, -- 파일 접근 시간 -// md5 TEXT, -- MD5 해시 -// sha256 TEXT, -- SHA-256 해시 -// entropy REAL, -- 엔트로피 (최대 1GB 파일) -// exif_metadata TEXT, -- EXIF 메타데이터 -// dublin_core TEXT, -- Dublin Core 메타데이터 -// yara_x_result TEXT, -- YARA-X 룰 결과 -// nsrl_check BOOLEAN, -- NSRL 체크 여부 -// scan_date DATETIME DEFAULT CURRENT_TIMESTAMP -- 스캔 날짜 -// ); -// ` -// -// _, err := t.db.Exec(sqlStmt) -// if err != nil { -// log.Fatal(err) -// } -//} diff --git a/Model/SystemInfoDB.go b/Model/SystemInfoDB.go index 1205243..e9d69d9 100644 --- a/Model/SystemInfoDB.go +++ b/Model/SystemInfoDB.go @@ -1,6 +1,7 @@ package Model import ( + "encoding/json" "errors" "fmt" "time" @@ -11,17 +12,17 @@ type SystemInfoDB struct { } type DsystemInfoDB struct { - id int - Uuid string - HostName string - OsName string - OsVersion string - Family string - Architecture string - KernelVersion string - BootTime time.Time - createAt time.Time - updateAt time.Time + ID int `json:"id"` + Uuid string `json:"uuid"` + HostName string `json:"host_name"` + OsName string `json:"os_name"` + OsVersion string `json:"os_version"` + Family string `json:"family"` + Architecture string `json:"architecture"` + KernelVersion string `json:"kernel_version"` + BootTime time.Time `json:"boot_time"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } func NewSystemInfoDB() *SystemInfoDB { @@ -29,7 +30,7 @@ func NewSystemInfoDB() *SystemInfoDB { return sysDB } -func (s *SystemInfoDB) createTable() error { +func (s *SystemInfoDB) CreateTable() error { db, err := getDBPtr() if err != nil { return err @@ -78,14 +79,14 @@ func (s *SystemInfoDB) createTable() error { return nil } -func (s *SystemInfoDB) insertRecord(data *DsystemInfoDB) error { +func (s *SystemInfoDB) InsertRecord(data *DsystemInfoDB) error { // 데이터 베이스에는 단 하나의 Row 만을 보장해야함 - isExist, err := s.existRecord() + isExist, err := s.ExistRecord() if err != nil { return err } if isExist == true { - err = s.updateRecord(data) + err = s.UpdateRecord(data) if err != nil { return err } @@ -125,14 +126,14 @@ func (s *SystemInfoDB) insertRecord(data *DsystemInfoDB) error { selectRecords()를 통해 반환된 DsystemInfoDB 객체의 값을 수정한 후, 수정된 객체를 updateRecord 함수의 매개변수로 전달합시오 */ -func (s *SystemInfoDB) updateRecord(data *DsystemInfoDB) error { +func (s *SystemInfoDB) UpdateRecord(data *DsystemInfoDB) error { db, err := getDBPtr() if err != nil { return err } defer db.Close() - rows, err := s.selectRecords() + rows, err := s.SelectRecords() if err != nil { return err } @@ -151,7 +152,7 @@ func (s *SystemInfoDB) updateRecord(data *DsystemInfoDB) error { return nil } -func (s *SystemInfoDB) deleteRecord(uuid string) error { +func (s *SystemInfoDB) DeleteRecord(uuid string) error { db, err := getDBPtr() if err != nil { return err @@ -167,7 +168,7 @@ func (s *SystemInfoDB) deleteRecord(uuid string) error { return nil } -func (s *SystemInfoDB) selectRecords() ([]DsystemInfoDB, error) { +func (s *SystemInfoDB) SelectRecords() ([]DsystemInfoDB, error) { db, err := getDBPtr() if err != nil { return nil, err @@ -185,9 +186,9 @@ func (s *SystemInfoDB) selectRecords() ([]DsystemInfoDB, error) { for row.Next() { var data DsystemInfoDB - err = row.Scan(&data.id, &data.Uuid, &data.HostName, &data.OsName, + err = row.Scan(&data.ID, &data.Uuid, &data.HostName, &data.OsName, &data.OsVersion, &data.Family, &data.Architecture, &data.KernelVersion, - &data.BootTime, &data.createAt, &data.updateAt) + &data.BootTime, &data.CreatedAt, &data.UpdatedAt) if err != nil { return nil, err } @@ -201,7 +202,7 @@ func (s *SystemInfoDB) selectRecords() ([]DsystemInfoDB, error) { * 하나 이상의 row 행이 있는지 검사한다. */ -func (s *SystemInfoDB) existRecord() (bool, error) { +func (s *SystemInfoDB) ExistRecord() (bool, error) { db, err := getDBPtr() if err != nil { return false, err @@ -217,3 +218,20 @@ func (s *SystemInfoDB) existRecord() (bool, error) { return exists, nil } + +func (s *SystemInfoDB) Unmarshal(data []byte) (*DsystemInfoDB, error) { + + var DsysInfo DsystemInfoDB + err := json.Unmarshal(data, &DsysInfo) + if err != nil { + fmt.Println("Error unmarshaling JSON:", err) + return &DsysInfo, err + } + + err = s.InsertRecord(&DsysInfo) + if err != nil { + return &DsysInfo, err + } + + return &DsysInfo, err +} diff --git a/Model/nosqldb.go b/Model/nosqldb.go index 94590e0..e6cd1f3 100644 --- a/Model/nosqldb.go +++ b/Model/nosqldb.go @@ -8,35 +8,47 @@ import ( "time" ) +// Chatgpt 이용함. /* -* -Mongodb는 100개의 커넥션 풀을 지원한다. +MongoDB는 100개의 커넥션 풀을 지원한다. +- 최대 풀 크기 50, 최소 풀 크기 10으로 설정. +- 커넥션 최대 유휴 시간을 30초로 설정. */ -func getNoSqlDbPtr() { - clientOptions := options.Client().ApplyURI("mongodb://localhost:27017"). - SetMaxPoolSize(50). - SetMinPoolSize(10). - SetMaxConnIdleTime(30 * time.Second) +func getNoSqlDbPtr() (*mongo.Database, error) { + // MongoDB 클라이언트 옵션 설정 + clientOptions := options.Client(). + ApplyURI("mongodb://localhost:27017"). // MongoDB URI + SetMaxPoolSize(50). // 최대 풀 크기 + SetMinPoolSize(10). // 최소 풀 크기 + SetMaxConnIdleTime(30 * time.Second) // 최대 유휴 시간 + // 클라이언트 생성 client, err := mongo.NewClient(clientOptions) if err != nil { - log.Fatal(err) + log.Fatal("Error creating MongoDB client: ", err) + return nil, err } // 연결 설정 ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel() + // MongoDB에 연결 err = client.Connect(ctx) if err != nil { - log.Fatal(err) + log.Fatal("Error connecting to MongoDB: ", err) + return nil, err } - defer func() { - if err := client.Disconnect(ctx); err != nil { - log.Fatal(err) - } - }() + // 사용할 데이터베이스 선택 (예: "mydatabase") + database := client.Database("mydatabase") - database := client.Database("") + // 프로시저 실행 + // 성공 ( success ) + // 실패 ( failure ) + // 경고 ( Warning ) + //S + + // 클라이언트 연결 반환 + return database, nil } From 37e67aaa7471144cae6b0d5ab1dc1556bca24126 Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Thu, 5 Sep 2024 21:51:49 +0900 Subject: [PATCH 06/26] =?UTF-8?q?HTTPS-53=20<=20JobManager=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/AgentManager.go | 40 --------- Core/CommandDispatcher.go | 174 +++++++++++++++++++------------------- Core/health_manager.go | 80 ------------------ 3 files changed, 88 insertions(+), 206 deletions(-) delete mode 100644 Core/AgentManager.go delete mode 100644 Core/health_manager.go diff --git a/Core/AgentManager.go b/Core/AgentManager.go deleted file mode 100644 index 6101c34..0000000 --- a/Core/AgentManager.go +++ /dev/null @@ -1,40 +0,0 @@ -package Core - -import "github.com/your/repo/Model" - -/* - Agent Model = Managing + model -*/ - -type AgentManager struct { -} - -func (self *AgentManager) createAgent(uuid string) error { - - return nil -} - -/* -agent 의 상태 Status 는 총 3가지로 나뉜다. - -Running : 동작중인 상태 -waiting : 대기중인 상태 -Stopping : 정지후 사라지기 전에 상태 -*/ -func (self *AgentManager) checkAgent(uuid string) bool { - - return false -} - -func (self *AgentManager) updateAgentStatus(uuid string, status bool) bool { - agtStat := &Model.NewAgentStatusDB() - record := &Model.AgentStatusRecord{ - UUID: uuid, - Status: status, - } - agtStat.UpdateRecord() -} - -func (self *AgentManager) deleteAgent(uuid string) bool { - -} diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index cdb0c1d..08ca0d6 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -5,32 +5,28 @@ import ( "github.com/HTTPs-omma/HSProtocol/HSProtocol" "github.com/your/repo/Model" ) + // https://github.com/HTTPs-omma/HSProtocol type CommandDispatcher struct { - } - - - - -func (cd *CommandDispatcher)action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { +func (cd *CommandDispatcher) action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { //hsMgr := HSProtocol.NewHSProtocolManager() switch hs.Command { - case 0b0000000001 : + case 0b0000000001: return updateHealth(hs) - case 0b0000000010 : + case 0b0000000010: return updateProtocol(hs) - case 0b0000000011 : + case 0b0000000011: return postSystemInfo(hs) - case 0b0000000100 : - break; // 예약 - case 0b0000000101 : + case 0b0000000100: + break // 예약 + case 0b0000000101: return postApplicationInfo(hs) - case 0b0000000110 : + case 0b0000000110: return getProcedure(hs) - case 0b0000000111 : + case 0b0000000111: return postLogOfProcedure(hs) } @@ -38,18 +34,16 @@ func (cd *CommandDispatcher)action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { } // Command: 1 (0b0000000001) -func updateHealth(hs *HSProtocol.HS)(*HSProtocol.HS, error){ +func updateHealth(hs *HSProtocol.HS) (*HSProtocol.HS, error) { agsmd := Model.NewAgentStatusDB() rst, err := agsmd.ExistRecord() if err != nil { return nil, err } - if( rst ) { + if rst { return nil, fmt.Errorf("Agent Status DB : no Records") } - - records, err := agsmd.SelectRecords() if err != nil { return nil, err @@ -57,9 +51,8 @@ func updateHealth(hs *HSProtocol.HS)(*HSProtocol.HS, error){ hs_uuid := string(hs.UUID[:]) - flag := false - for _, record := range records { + for _, record := range records { if record.UUID == hs_uuid { flag = true } @@ -67,41 +60,40 @@ func updateHealth(hs *HSProtocol.HS)(*HSProtocol.HS, error){ if flag == true { agsmd.UpdateRecord(&Model.AgentStatusRecord{ - UUID : string(hs.UUID[:]), + UUID: string(hs.UUID[:]), Status: Model.BinaryToAgentStatus(hs.HealthStatus), }) return &HSProtocol.HS{ // ACK - ProtocolID: hs.ProtocolID, - Command: 0b0000000000, - UUID: hs.UUID, - HealthStatus: hs.HealthStatus, + ProtocolID: hs.ProtocolID, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, Identification: hs.Identification, - TotalLength: hs.TotalLength, - Data: []byte{}, + TotalLength: hs.TotalLength, + Data: []byte{}, }, nil - } else if (flag == false) && ( hs.HealthStatus == uint8(Model.Waiting) ) { + } else if (flag == false) && (hs.HealthStatus == uint8(Model.Waiting)) { agsmd.InsertRecord(&Model.AgentStatusRecord{ - UUID : string(hs.UUID[:]), + UUID: string(hs.UUID[:]), Status: Model.BinaryToAgentStatus(hs.HealthStatus), }) return &HSProtocol.HS{ // ACK - ProtocolID : hs.ProtocolID, - Command: 0b0000000000, - UUID: hs.UUID, - HealthStatus: hs.HealthStatus, + ProtocolID: hs.ProtocolID, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, Identification: hs.Identification, - TotalLength: hs.TotalLength, - Data: []byte{}, + TotalLength: hs.TotalLength, + Data: []byte{}, }, nil } - return nil, fmt.Errorf("incorrect AgentStatusRecords") } // Command: 2 (0b0000000010) -func updateProtocol(hs *HSProtocol.HS)(*HSProtocol.HS, error){ +func updateProtocol(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // protocolID := binary.BigEndian.Uint32(hs.Data) agsmd := Model.NewAgentStatusDB() @@ -109,20 +101,19 @@ func updateProtocol(hs *HSProtocol.HS)(*HSProtocol.HS, error){ if err != nil { return nil, err } - if( rst ) { + if rst { return nil, fmt.Errorf("Agent Status DB : no Records") } - records, err := agsmd.SelectRecords() if err != nil { return nil, err } hs_uuid := string(hs.UUID[:]) - for _, record := range records { + for _, record := range records { if record.UUID == hs_uuid { - record.Protocol = Model.BinaryToProtocol( hs.ProtocolID ) + record.Protocol = Model.BinaryToProtocol(hs.ProtocolID) err = agsmd.UpdateRecord(&record) if err != nil { return nil, err @@ -130,22 +121,19 @@ func updateProtocol(hs *HSProtocol.HS)(*HSProtocol.HS, error){ } } - return &HSProtocol.HS{ // ACK - ProtocolID: hs.ProtocolID, - Command: 0b0000000000, - UUID: hs.UUID, - HealthStatus: hs.HealthStatus, + ProtocolID: hs.ProtocolID, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, Identification: hs.Identification, - TotalLength: hs.TotalLength, - Data: []byte{}, + TotalLength: hs.TotalLength, + Data: []byte{}, }, nil } - // Command: 3 (0b0000000011) -func postSystemInfo (hs *HSProtocol.HS)(*HSProtocol.HS, error){ - +func postSystemInfo(hs *HSProtocol.HS) (*HSProtocol.HS, error) { sysDB := Model.NewSystemInfoDB() Dsys, err := sysDB.Unmarshal(hs.Data) @@ -159,81 +147,95 @@ func postSystemInfo (hs *HSProtocol.HS)(*HSProtocol.HS, error){ } return &HSProtocol.HS{ // ACK - ProtocolID: hs.ProtocolID, - Command: 0b0000000000, - UUID: hs.UUID, - HealthStatus: hs.HealthStatus, + ProtocolID: hs.ProtocolID, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, Identification: hs.Identification, - TotalLength: hs.TotalLength, - Data: []byte{}, + TotalLength: hs.TotalLength, + Data: []byte{}, }, nil } - // Command: 5 (0b0000000101) -func postApplicationInfo (hs *HSProtocol.HS)(*HSProtocol.HS, error){ +func postApplicationInfo(hs *HSProtocol.HS) (*HSProtocol.HS, error) { appDB := Model.ApplicationDB{} Dapp, err := appDB.Unmarshal(hs.Data) if err != nil { return nil, err } - err = appDB.InsertRecord( Dapp ) + err = appDB.InsertRecord(Dapp) if err != nil { return nil, err } return &HSProtocol.HS{ // ACK - ProtocolID: hs.ProtocolID, - Command: 0b0000000000, - UUID: hs.UUID, - HealthStatus: hs.HealthStatus, + ProtocolID: hs.ProtocolID, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, Identification: hs.Identification, - TotalLength: hs.TotalLength, - Data: []byte{}, + TotalLength: hs.TotalLength, + Data: []byte{}, }, nil } - - // Command: 6 (0b0000000110) -func getProcedure (hs *HSProtocol.HS)(*HSProtocol.HS, error){ +func getProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { appDB := Model.ApplicationDB{} Dapp, err := appDB.Unmarshal(hs.Data) if err != nil { return nil, err } - err = appDB.InsertRecord( Dapp ) + err = appDB.InsertRecord(Dapp) if err != nil { return nil, err } return &HSProtocol.HS{ // ACK - ProtocolID: hs.ProtocolID, - Command: 0b0000000000, - UUID: hs.UUID, - HealthStatus: hs.HealthStatus, + ProtocolID: hs.ProtocolID, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, Identification: hs.Identification, - TotalLength: hs.TotalLength, - Data: []byte{}, + TotalLength: hs.TotalLength, + Data: []byte{}, }, nil } // Command: 7 (0b0000000111) -func postLogOfProcedure (hs *HSProtocol.HS)(*HSProtocol.HS, error){ +func postLogOfProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { - Model. + jbMgr := NewJobManager() + var agentUuid string + copy(hs.UUID[:], agentUuid) + job, exist := jbMgr.GetData(agentUuid) + if exist == true { + + // technical ID 에 맵핑하여 yaml 파일을 직렬화하고 불러와서 + + return &HSProtocol.HS{ // ACK + ProtocolID: hs.ProtocolID, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + }, nil + } + + // false return &HSProtocol.HS{ // ACK - ProtocolID : hs.ProtocolID, - Command: 0b0000000000, - UUID: hs.UUID, - HealthStatus: hs.HealthStatus, + ProtocolID: hs.ProtocolID, + Command: 0b0000000000, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, Identification: hs.Identification, - TotalLength: hs.TotalLength, - Data: []byte{}, + TotalLength: hs.TotalLength, + Data: []byte{}, }, nil } - - diff --git a/Core/health_manager.go b/Core/health_manager.go deleted file mode 100644 index e54a6c0..0000000 --- a/Core/health_manager.go +++ /dev/null @@ -1,80 +0,0 @@ -package Core - -// 이거 보세요 -> https://d2.naver.com/helloworld/8588537 -import ( - "encoding/json" - "github.com/your/repo/Model" - "net" - "os" - "strconv" -) - -type HealthMsg struct { - UUID string `json:"uuid"` - Status int `json:"status"` -} - -/* -Let Check Example -refer : https://gist.github.com/miguelmota/01ba5131838ae31947ac9b03e57f3773 -*/ -func Heartbeat() { - - // UDP 열기 : HealthCheck - port, err := strconv.Atoi(os.Getenv("PORT")) - conn, err := net.ListenUDP("udp", &net.UDPAddr{ - Port: port, - IP: net.ParseIP("0.0.0.0"), - }) - if err != nil { - panic(err) - } - - go func() { - for { - message := make([]byte, 1024) - n, _, err := conn.ReadFromUDP(message[:]) - if err != nil { - panic(err) - } - if n == 0 { - continue - } - - hmsg := &HealthMsg{} - // json 역질렬화, Unmarshal - err = json.Unmarshal(message[:n], &hmsg) - if err != nil { - panic(err) - } - - agtstatdb := Model.NewAgentStatusDB() - - agtstatRcrd := Model.AgentStatusRecord{ - UUID: hmsg.UUID, - Status: getStatusType(hmsg.Status), - } - - err = agtstatdb.UpdateRecord(&agtstatRcrd) - if err != nil { - panic(err) // 에러처리를 바꿔야함 - } - } - - defer conn.Close() - }() - -} - -func getStatusType(status int) Model.AgentStatus { - - switch status { - case 0: - return Model.Running - case 1: - return Model.Waiting - case 2: - return Model.Stopping - } - return Model.Stopping -} From e4cdbcb2e24914e3a078ba8e88702948817ced1a Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Thu, 5 Sep 2024 21:57:44 +0900 Subject: [PATCH 07/26] =?UTF-8?q?HTTPS-53=20<=20JobManager=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/JobManager.go | 47 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 Core/JobManager.go diff --git a/Core/JobManager.go b/Core/JobManager.go new file mode 100644 index 0000000..ce2a0e7 --- /dev/null +++ b/Core/JobManager.go @@ -0,0 +1,47 @@ +package Core + +import ( + "time" +) + +type JobData struct { + TechnicalID string `json:"technicalID"` + AgentUUID string `json:"agentUUID"` + MessageUUID string `json:"messageUUID"` + createAt time.Time +} + +type JobManager struct { + dataMap map[string][]JobData +} + +func NewJobManager() *JobManager { + return &JobManager{ + dataMap: make(map[string][]JobData), + } +} + +func popFront(slice []JobData) (JobData, []JobData) { + if len(slice) > 0 { + job := slice[0] + return job, slice[1:] + } + return slice[0], slice +} + +func (jm *JobManager) GetData(agentUUID string) (*JobData, bool) { + jobs, exists := jm.dataMap[agentUUID] + + if len(jobs) > 0 { + var job JobData + job, jm.dataMap[agentUUID] = popFront(jobs) + return &job, exists + } + + return &JobData{}, exists +} + +func (jm *JobManager) insertData(jobData JobData) bool { + jm.dataMap[jobData.AgentUUID] = append(jm.dataMap[jobData.AgentUUID], jobData) + return true +} From a0b89b6b3a94784b9045e3571a3a2e75360f8638 Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Mon, 9 Sep 2024 19:56:42 +0900 Subject: [PATCH 08/26] =?UTF-8?q?HTTPS-53=20<=20gitIgnore=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitIgnore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitIgnore b/.gitIgnore index e69de29..2eea525 100644 --- a/.gitIgnore +++ b/.gitIgnore @@ -0,0 +1 @@ +.env \ No newline at end of file From 83f3bce9b0975db7cd13f7e9bd6cbdc8d33687f8 Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Mon, 9 Sep 2024 21:12:44 +0900 Subject: [PATCH 09/26] =?UTF-8?q?HTTPS-53=20<=20gitIgnore=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitIgnore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitIgnore b/.gitIgnore index 2eea525..db230f5 100644 --- a/.gitIgnore +++ b/.gitIgnore @@ -1 +1,2 @@ -.env \ No newline at end of file +Model/.env +./.env \ No newline at end of file From 688650ab9499d9a85f021b2704af2bd9605c467e Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Mon, 9 Sep 2024 21:13:14 +0900 Subject: [PATCH 10/26] =?UTF-8?q?HTTPS-53=20<=20nosqldb=20model=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 2 - Core/CommandDispatcher.go | 1 + Core/JobManager.go | 1 + Model/ApplicationDB.go | 22 --------- Model/ApplicationDB_test.go | 91 ---------------------------------- Model/OperationLog.go | 99 +++++++++++++++++++++++++++++++++++++ Model/OperationLog_test.go | 94 +++++++++++++++++++++++++++++++++++ Model/SystemInfoDB_test.go | 4 +- Model/nosqldb.go | 23 ++++----- 9 files changed, 206 insertions(+), 131 deletions(-) delete mode 100644 .env create mode 100644 Model/OperationLog.go create mode 100644 Model/OperationLog_test.go diff --git a/.env b/.env deleted file mode 100644 index a845f51..0000000 --- a/.env +++ /dev/null @@ -1,2 +0,0 @@ -SERVERPROT=8080 -CHECKHEALTHPORT=8081 diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index 08ca0d6..c5c26eb 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -213,6 +213,7 @@ func postLogOfProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { copy(hs.UUID[:], agentUuid) job, exist := jbMgr.GetData(agentUuid) + if exist == true { // technical ID 에 맵핑하여 yaml 파일을 직렬화하고 불러와서 diff --git a/Core/JobManager.go b/Core/JobManager.go index ce2a0e7..22bb214 100644 --- a/Core/JobManager.go +++ b/Core/JobManager.go @@ -43,5 +43,6 @@ func (jm *JobManager) GetData(agentUUID string) (*JobData, bool) { func (jm *JobManager) insertData(jobData JobData) bool { jm.dataMap[jobData.AgentUUID] = append(jm.dataMap[jobData.AgentUUID], jobData) + return true } diff --git a/Model/ApplicationDB.go b/Model/ApplicationDB.go index 868fca6..bcbc91e 100644 --- a/Model/ApplicationDB.go +++ b/Model/ApplicationDB.go @@ -3,9 +3,6 @@ package Model import ( "encoding/json" "fmt" - "github.com/yusufpapurcu/wmi" - "log" - "strings" "time" ) @@ -146,25 +143,6 @@ type Win32_Product struct { Description string // 제품 설명 } -func GetApplicationList() []Win32_Product { - var dst []Win32_Product - query := "SELECT Name, AgentUUID, Version, Language, Vendor, InstallDate2, InstallLocation, InstallSource, PackageName, PackageCode, RegCompany, RegOwner, URLInfoAbout, Description FROM Win32_Product" - err := wmi.Query(query, &dst) - if err != nil { - log.Fatalf("wmi query failed: %v", err) - } - for i := range dst { - input := dst[i].PackageCode - if strings.HasPrefix(input, "{") && strings.HasSuffix(input, "}") { - input = strings.Replace(input, "{", "", 1) - input = strings.Replace(input, "}", "", 1) - } - dst[i].PackageCode = input - } - - return dst -} - func (a *ApplicationDB) InsertRecord(data *DapplicationDB) error { // ProductID 가 있는지 확인 후 중복되는 것이 없으면 insert 하기 diff --git a/Model/ApplicationDB_test.go b/Model/ApplicationDB_test.go index c7eb07f..ad1cbde 100644 --- a/Model/ApplicationDB_test.go +++ b/Model/ApplicationDB_test.go @@ -57,97 +57,6 @@ func TestApplicationDB_CRUD(t1 *testing.T) { for _, tt := range tests { t1.Run(tt.name, func(t *testing.T) { - // ============ Create 테스트 ================ - appdb := NewApplicationDB() - appdb.createTable() - - wind32 := getApplicationList()[0] - data := DapplicationDB{} - data.Name = wind32.Name - data.Description = wind32.Description - data.Version = wind32.Version - data.Vendor = wind32.Vendor - data.InstallDate2 = wind32.InstallDate2 - data.InstallLocation = wind32.InstallLocation - data.InstallSource = wind32.InstallSource - data.Language = wind32.Language - data.PackageCode = wind32.PackageCode - data.PackageName = wind32.PackageName - data.RegCompany = wind32.RegCompany - data.RegOwner = wind32.RegOwner - data.URLInfoAbout = wind32.URLInfoAbout - - err := appdb.insertRecord(data) - if err != nil { - t.Fatalf(appdb.dbName + " : insert 에러\n" + err.Error()) - } - - // ========== Create 검증 ============= - dbPtr, err := getDBPtr() - if err != nil { - t.Fatalf(appdb.dbName + " : DB 포인터를 가져올 수 없습니다. getDBPtr() 함수 오류\n" + err.Error()) - } - - query := fmt.Sprintf("select * from %s", appdb.dbName) - data2 := &DapplicationDB{} - row := dbPtr.QueryRow(query) - if err != nil { - t.Fatalf(appdb.dbName + " : select Qeury 오류\n" + err.Error()) - } - - err = row.Scan(&data2.ID, &data2.Name, &data2.Version, &data2.Language, &data2.Vendor, - &data2.InstallDate2, &data2.InstallLocation, &data2.InstallSource, &data2.PackageName, - &data2.PackageCode, &data2.RegCompany, &data2.RegOwner, &data2.URLInfoAbout, &data2.Description, - &data2.isDeleted, &data2.CreateAt, &data2.UpdateAt, &data2.deletedAt) - - if err != nil { - t.Fatalf(appdb.dbName + " : DapplicationDB 내용이 실제 DB 컬럼 내용과 일치하지 않습니다.\n" + err.Error()) - } - - assert.Equal(t, data2.URLInfoAbout, data.URLInfoAbout) - assert.Equal(t, data2.Name, data.Name) - assert.Equal(t, data2.RegCompany, data.RegCompany) - assert.Equal(t, data2.RegOwner, data.RegOwner) - assert.Equal(t, data2.Language, data.Language) - assert.Equal(t, data2.InstallSource, data.InstallSource) - assert.Equal(t, data2.InstallDate2, data.InstallDate2) - assert.Equal(t, data2.Description, data.Description) - assert.Equal(t, data2.Version, data.Version) - - // ============ Read 테스트 ================ - data3, err := appdb.selectAllRecords() - data4 := data3[0] - if err != nil { - t1.Fatalf("select 테스트 에러\n" + err.Error()) - } - - assert.Equal(t, data2.URLInfoAbout, data4.URLInfoAbout) - assert.Equal(t, data2.Name, data4.Name) - assert.Equal(t, data2.RegCompany, data4.RegCompany) - assert.Equal(t, data2.RegOwner, data4.RegOwner) - assert.Equal(t, data2.Language, data4.Language) - assert.Equal(t, data2.InstallSource, data4.InstallSource) - assert.Equal(t, data2.InstallDate2, data4.InstallDate2) - assert.Equal(t, data2.Description, data4.Description) - assert.Equal(t, data2.Version, data4.Version) - - // ============ Delete 테스트 ================ - data6, err := appdb.selectByPackageCode(data.PackageCode) - if err != nil { - t1.Fatalf(": selectByPackageCode 실패\n" + err.Error()) - } - assert.NotEqual(t, data6.PackageCode, "-1") - - err = appdb.deleteByPackageCode(data.PackageCode) - if err != nil { - t1.Fatalf("삭제 실패\n" + err.Error()) - } - - data7, err := appdb.selectByPackageCode(data.PackageCode) - if err != nil { - t1.Fatalf(": selectByPackageCode 실패\n" + err.Error()) - } - assert.Equal(t, data7.PackageCode, "-1") }) } } diff --git a/Model/OperationLog.go b/Model/OperationLog.go new file mode 100644 index 0000000..e5d8728 --- /dev/null +++ b/Model/OperationLog.go @@ -0,0 +1,99 @@ +package Model + +import ( + "context" + "fmt" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "time" +) + +/* +빠른 개발을 위해 chatgpt 를 사용한 개발 코드입니다. +검토자 : 허남정 +*/ + + +// OperationLogDocument 구조체 정의 +type OperationLogDocument struct { + ID primitive.ObjectID `bson:"_id,omitempty"` + AgentUUID string `bson:"agentUUID"` + ProcedureID string `bson:"procedureID"` + InstructionUUID string `bson:"instructionUUID"` + ConductAt time.Time `bson:"conductAt"` + ExitCode int `bson:"exitCode"` + Log string `bson:"log"` + Command string `bson:"command"` // Command 필드로 변경 +} + +// OperationLogDB는 CRUD 작업을 수행하는 구조체입니다. +type OperationLogDB struct { + Collection *mongo.Collection +} + +// NewOperationLogDB는 OperationLogDB 인스턴스를 생성합니다. +func NewOperationLogDB() (*OperationLogDB, error) { + db, err := getCollectionPtr() + if err != nil { + return nil, err + } + return &OperationLogDB{ + Collection: db.Collection("execLog"), + }, nil +} + +// Create는 새로운 OperationLogDocument 문서를 MongoDB에 삽입합니다. +func (repo *OperationLogDB) insertDocument(log OperationLogDocument) (*mongo.InsertOneResult, error) { + // Command 필드를 기본값으로 설정 (필요에 따라 변경) + result, err := repo.Collection.InsertOne(context.TODO(), log) + fmt.Println(log) + if err != nil { + return nil, err + } + + fmt.Println("Inserted document with ID:", result.InsertedID) + return result, nil +} + +// Read는 OperationLogDocument 문서를 조회합니다. +func (repo *OperationLogDB) selectDocumentById(id string) (*OperationLogDocument, error) { + var OperationLogDocument OperationLogDocument + filter := bson.M{"instructionUUID": id} + + err := repo.Collection.FindOne(context.TODO(), filter).Decode(&OperationLogDocument) + if err != nil { + return nil, err + } + + return &OperationLogDocument, nil +} + +// Update는 OperationLogDocument 문서를 수정합니다. +func (repo *OperationLogDB) UpdateDocumentByInstID(id string, updateData bson.M) (*mongo.UpdateResult, error) { + filter := bson.M{"instructionUUID": id} + update := bson.M{ + "$set": updateData, + } + + result, err := repo.Collection.UpdateOne(context.TODO(), filter, update) + if err != nil { + return nil, err + } + + fmt.Println("Updated document count:", result.ModifiedCount) + return result, nil +} + +// Delete는 OperationLogDocument 문서를 삭제합니다. +func (repo *OperationLogDB) DeleteDocumentByInstID(id string) (*mongo.DeleteResult, error) { + filter := bson.M{"instructionUUID": id} + + result, err := repo.Collection.DeleteOne(context.TODO(), filter) + if err != nil { + return nil, err + } + + fmt.Println("Deleted document count:", result.DeletedCount) + return result, nil +} diff --git a/Model/OperationLog_test.go b/Model/OperationLog_test.go new file mode 100644 index 0000000..651122f --- /dev/null +++ b/Model/OperationLog_test.go @@ -0,0 +1,94 @@ +package Model + +import ( + "fmt" + "github.com/joho/godotenv" + "log" + "testing" + "time" +) + +func TestInsertDocument(t *testing.T) { + tests := []struct { + name string + log OperationLogDocument + }{ + { + name: "Insert valid document", + log: OperationLogDocument{ + AgentUUID: "agent-123", + ProcedureID: "tech-456", + InstructionUUID: "msg-789", + ConductAt: time.Now(), + ExitCode: 0, + Log: "Test log message", + Command: "Test command", + }, + }, + } + + for _, tt := range tests { + + // MongoDB 클라이언트 옵션 설정 + err := godotenv.Load(".env") + if err != nil { + log.Fatal("Error loading .env file") + } + + t.Run(tt.name, func(t *testing.T) { + db, err := NewOperationLogDB() + if err != nil { + log.Fatal("에러: ", err) + } + + // insertDocument 호출 + result, err := db.insertDocument(tt.log) + if err != nil { + t.Errorf("insertDocument() 에러: %v", err) + } + + // 결과 ID가 있는지 확인 + if result == nil || result.InsertedID == nil { + t.Errorf("insertDocument() 결과가 유효하지 않습니다.") + } else { + t.Logf("삽입된 문서 ID: %v", result.InsertedID) + } + + log, err := db.selectDocumentById(tt.log.InstructionUUID) + if err != nil { + t.Fatalf("select 오류") + } + fmt.Printf("성공 : " + log.InstructionUUID) + + //rst2, err := db.UpdateDocumentByInstID(tt.log.InstructionUUID, + //&OperationLogDocument{ + // AgentUUID: "agent-123", + // ProcedureID: "tech-456", + // InstructionUUID: "msg-789", + // ConductAt: time.Now(), + // ExitCode: 0, + // Log: "Test log message", + // Command: "Test command", + //}) + //if err == nil { + // t.Fatalf("update 오류") + //} + + + rst, err := db.DeleteDocumentByInstID(tt.log.InstructionUUID) + if err != nil { + t.Errorf("DeleteDocumentByInstID() 에러: %v", err) + } + // 결과 ID가 있는지 확인 + if rst == nil || rst.DeletedCount == 0 { + t.Errorf("DeleteDocument() 결과가 유효하지 않습니다.") + } else { + t.Logf("정상적으로 삭제됨") + //t.Logf("삭제된 문서 ID: %v", rst.) + } + + + + }) + } +} diff --git a/Model/SystemInfoDB_test.go b/Model/SystemInfoDB_test.go index 4aee3df..cbca6a5 100644 --- a/Model/SystemInfoDB_test.go +++ b/Model/SystemInfoDB_test.go @@ -26,7 +26,7 @@ func TestSystemInfoDB_createTable(t *testing.T) { t.Run(tt.name, func(t *testing.T) { var err error s := NewSystemInfoDB() - s.createTable() + s.CreateTable() if err != nil { t.Fatalf(s.dbName + " : DB를 생성할 수 없습니다. \n" + err.Error()) } @@ -67,7 +67,7 @@ func TestNewSystemInfoDB_selectRecord(t *testing.T) { var err error s := NewSystemInfoDB() - data, err := s.selectRecords() + data, err := s.SelectRecords() if err != nil { t.Fatalf(s.dbName + " : select 오류. Query 재 확인 \n" + err.Error()) diff --git a/Model/nosqldb.go b/Model/nosqldb.go index e6cd1f3..70b4022 100644 --- a/Model/nosqldb.go +++ b/Model/nosqldb.go @@ -5,6 +5,7 @@ import ( "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "log" + "os" "time" ) @@ -14,13 +15,14 @@ MongoDB는 100개의 커넥션 풀을 지원한다. - 최대 풀 크기 50, 최소 풀 크기 10으로 설정. - 커넥션 최대 유휴 시간을 30초로 설정. */ -func getNoSqlDbPtr() (*mongo.Database, error) { - // MongoDB 클라이언트 옵션 설정 +func getCollectionPtr() (*mongo.Database, error) { + MONGOID := os.Getenv("MONGODBID") + MONGOPW := os.Getenv("MONGODBPW") clientOptions := options.Client(). - ApplyURI("mongodb://localhost:27017"). // MongoDB URI - SetMaxPoolSize(50). // 최대 풀 크기 - SetMinPoolSize(10). // 최소 풀 크기 - SetMaxConnIdleTime(30 * time.Second) // 최대 유휴 시간 + ApplyURI("mongodb://" + MONGOID + ":" + MONGOPW + "@uskawjdu.iptime.org:17017/"). // MongoDB URI + SetMaxPoolSize(50). // 최대 풀 크기 + SetMinPoolSize(10). // 최소 풀 크기 + SetMaxConnIdleTime(30 * time.Second) // 최대 유휴 시간 // 클라이언트 생성 client, err := mongo.NewClient(clientOptions) @@ -40,14 +42,7 @@ func getNoSqlDbPtr() (*mongo.Database, error) { return nil, err } - // 사용할 데이터베이스 선택 (예: "mydatabase") - database := client.Database("mydatabase") - - // 프로시저 실행 - // 성공 ( success ) - // 실패 ( failure ) - // 경고 ( Warning ) - //S + database := client.Database("httpsAgent") // 클라이언트 연결 반환 return database, nil From 3c2d3729eb9370c8632f1bea80e76482e94a61ef Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Mon, 9 Sep 2024 21:27:57 +0900 Subject: [PATCH 11/26] =?UTF-8?q?HTTPS-53=20<=20Command=20=EB=A5=BC=20enum?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=8C=80=EC=B2=B4=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/CommandDispatcher.go | 54 ++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index c5c26eb..cfbcba9 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -10,23 +10,35 @@ import ( type CommandDispatcher struct { } +// Command 상수를 정의 +const ( + ACK = 0b0000000000 + UPDATE_HEALTH = 0b0000000001 + UPDATE_PROTOCOL = 0b0000000010 + POST_SYSTEM_INFO = 0b0000000011 + RESERVED = 0b0000000100 + POST_APPLICATION_INFO = 0b0000000101 + GET_PROCEDURE = 0b0000000110 + POST_LOG_OF_PROCEDURE = 0b0000000111 +) + func (cd *CommandDispatcher) action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { - //hsMgr := HSProtocol.NewHSProtocolManager() + // hsMgr := HSProtocol.NewHSProtocolManager() switch hs.Command { - case 0b0000000001: + case UPDATE_HEALTH: return updateHealth(hs) - case 0b0000000010: + case UPDATE_PROTOCOL: return updateProtocol(hs) - case 0b0000000011: + case POST_SYSTEM_INFO: return postSystemInfo(hs) - case 0b0000000100: + case RESERVED: break // 예약 - case 0b0000000101: + case POST_APPLICATION_INFO: return postApplicationInfo(hs) - case 0b0000000110: + case GET_PROCEDURE: return getProcedure(hs) - case 0b0000000111: + case POST_LOG_OF_PROCEDURE: return postLogOfProcedure(hs) } @@ -65,7 +77,7 @@ func updateHealth(hs *HSProtocol.HS) (*HSProtocol.HS, error) { }) return &HSProtocol.HS{ // ACK ProtocolID: hs.ProtocolID, - Command: 0b0000000000, + Command: ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -80,7 +92,7 @@ func updateHealth(hs *HSProtocol.HS) (*HSProtocol.HS, error) { return &HSProtocol.HS{ // ACK ProtocolID: hs.ProtocolID, - Command: 0b0000000000, + Command: ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -123,7 +135,7 @@ func updateProtocol(hs *HSProtocol.HS) (*HSProtocol.HS, error) { return &HSProtocol.HS{ // ACK ProtocolID: hs.ProtocolID, - Command: 0b0000000000, + Command: ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -148,7 +160,7 @@ func postSystemInfo(hs *HSProtocol.HS) (*HSProtocol.HS, error) { return &HSProtocol.HS{ // ACK ProtocolID: hs.ProtocolID, - Command: 0b0000000000, + Command: ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -172,7 +184,7 @@ func postApplicationInfo(hs *HSProtocol.HS) (*HSProtocol.HS, error) { return &HSProtocol.HS{ // ACK ProtocolID: hs.ProtocolID, - Command: 0b0000000000, + Command: ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -196,7 +208,7 @@ func getProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { return &HSProtocol.HS{ // ACK ProtocolID: hs.ProtocolID, - Command: 0b0000000000, + Command: ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -208,19 +220,19 @@ func getProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // Command: 7 (0b0000000111) func postLogOfProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { - jbMgr := NewJobManager() + jbMgr := NewJobManager() // stack 에 있어야겠지? + var agentUuid string copy(hs.UUID[:], agentUuid) - job, exist := jbMgr.GetData(agentUuid) - - if exist == true { + job, exist := jbMgr.GetData(agentUuid) // agentuuid 에 해당하는 값 찾아괴 - // technical ID 에 맵핑하여 yaml 파일을 직렬화하고 불러와서 + if exist == true { // job 이 있다면 + // procedureID 에 맵핑하여 yaml 파일을 직렬화하고 불러와서 return &HSProtocol.HS{ // ACK ProtocolID: hs.ProtocolID, - Command: 0b0000000000, + Command: ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -232,7 +244,7 @@ func postLogOfProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // false return &HSProtocol.HS{ // ACK ProtocolID: hs.ProtocolID, - Command: 0b0000000000, + Command: ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, From ccb8d611ea4732f1ba32e38fda7835de54da8100 Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Mon, 9 Sep 2024 23:34:37 +0900 Subject: [PATCH 12/26] =?UTF-8?q?HTTPS-53=20<=20ymal=20Roader=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitIgnore | 2 +- .idea/vcs.xml | 1 + CommandDB | 1 + Core/CommandDispatcher.go | 26 ++++++-- Core/CommandManager.go | 124 ++++++++++++++++++++++++++++++++++++ Core/CommandManager_test.go | 23 +++++++ Core/JobManager.go | 69 ++++++++++++-------- Model/JobData.go | 100 +++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 2 + 10 files changed, 315 insertions(+), 34 deletions(-) create mode 160000 CommandDB create mode 100644 Core/CommandManager.go create mode 100644 Core/CommandManager_test.go create mode 100644 Model/JobData.go diff --git a/.gitIgnore b/.gitIgnore index db230f5..bb32ee7 100644 --- a/.gitIgnore +++ b/.gitIgnore @@ -1,2 +1,2 @@ Model/.env -./.env \ No newline at end of file +.env \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 35eb1dd..7575a9f 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/CommandDB b/CommandDB new file mode 160000 index 0000000..0966d55 --- /dev/null +++ b/CommandDB @@ -0,0 +1 @@ +Subproject commit 0966d550f70a356a06b204d0c5e9bc01110479b5 diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index cfbcba9..3a06493 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -220,16 +220,32 @@ func getProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // Command: 7 (0b0000000111) func postLogOfProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { - jbMgr := NewJobManager() // stack 에 있어야겠지? - + jbMgr, err := NewJobManager() // stack 에 있어야겠지? + if err != nil { + return nil, err + } var agentUuid string copy(hs.UUID[:], agentUuid) + job, err, exist := jbMgr.popData(agentUuid) - job, exist := jbMgr.GetData(agentUuid) // agentuuid 에 해당하는 값 찾아괴 + if err != nil { + return nil, err + } if exist == true { // job 이 있다면 - // procedureID 에 맵핑하여 yaml 파일을 직렬화하고 불러와서 + cmdMgr, err := NewCommandManager() + if err != nil { + return nil, err + } + cmdData, issuccess := cmdMgr.GetByID(job.ProcedureID) // 프로시저를 불러와야함. + if issuccess != true { + return nil, fmt.Errorf("job procedure not found") + } + bData, err := cmdData.ToBytes() + if err != nil { + return nil, err + } return &HSProtocol.HS{ // ACK ProtocolID: hs.ProtocolID, Command: ACK, @@ -237,7 +253,7 @@ func postLogOfProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { HealthStatus: hs.HealthStatus, Identification: hs.Identification, TotalLength: hs.TotalLength, - Data: []byte{}, + Data: bData, }, nil } diff --git a/Core/CommandManager.go b/Core/CommandManager.go new file mode 100644 index 0000000..9e79c84 --- /dev/null +++ b/Core/CommandManager.go @@ -0,0 +1,124 @@ +package Core + +import ( + "fmt" + "gopkg.in/yaml.v2" + "io/ioutil" + "log" + "os" + "path/filepath" +) + +/** +ChatGpt 로 생성한 코드임 +*/ + +// CommandData는 주어진 YAML 데이터를 저장할 구조체입니다. +type CommandData struct { + ID string `yaml:"id"` + MITREID string `yaml:"MITRE_ID"` + Description string `yaml:"Description"` + Tool string `yaml:"tool"` + RequisiteCommand string `yaml:"requisite_command"` + Command string `yaml:"command"` + Cleanup string `yaml:"cleanup"` +} + +// ToBytes는 CommandData 구조체를 YAML 바이트 슬라이스로 변환하는 함수입니다. +func (cd *CommandData) ToBytes() ([]byte, error) { + // YAML로 직렬화 + data, err := yaml.Marshal(cd) + if err != nil { + return nil, err + } + return data, nil +} + +// CommandManager는 모든 CommandData를 관리하는 구조체입니다. +type CommandManager struct { + commands map[string]CommandData +} + +// NewCommandManager는 CommandManager를 초기화하고 YAML 파일들을 읽어들입니다. +func NewCommandManager() (*CommandManager, error) { + cm := &CommandManager{commands: make(map[string]CommandData)} + + err := cm.loadCommands() + if err != nil { + return nil, err + } + + return cm, nil +} + +// loadCommands는 주어진 경로에서 모든 YAML 파일을 읽어들여 CommandData로 변환합니다. +func (cm *CommandManager) loadCommands() error { + // 디렉토리 내의 모든 YAML 파일을 찾습니다. + files, err := filepath.Glob(filepath.Join("../CommandDB/", "*.yaml")) + if err != nil { + return fmt.Errorf("failed to read directory: %w", err) + } + + // 각 파일을 읽고 CommandData로 변환 + for _, file := range files { + err := cm.loadCommandFile(file) + if err != nil { + log.Printf("failed to load file %s: %v\n", file, err) + } + } + + return nil +} + +// loadCommandFile은 하나의 YAML 파일을 읽어 CommandData로 변환하고 저장합니다. +func (cm *CommandManager) loadCommandFile(filepath string) error { + file, err := os.Open(filepath) + if err != nil { + return fmt.Errorf("failed to open file: %w", err) + } + defer file.Close() + + // 파일 내용 읽기 + data, err := ioutil.ReadAll(file) + if err != nil { + return fmt.Errorf("failed to read file: %w", err) + } + + // YAML 데이터를 CommandData 구조체로 변환 + var command CommandData + err = yaml.Unmarshal(data, &command) + if err != nil { + return fmt.Errorf("failed to unmarshal yaml: %w", err) + } + + // ID를 키로 맵에 저장 + cm.commands[command.ID] = command + + return nil +} + +// GetByID는 주어진 ID에 해당하는 CommandData를 반환합니다. +func (cm *CommandManager) GetByID(id string) (*CommandData, bool) { + command, exists := cm.commands[id] + if !exists { + return nil, false + } + return &command, true +} + +//func main() { +// // ../CommandDB/ 디렉토리에 있는 모든 YAML 파일을 읽어 CommandManager를 초기화합니다. +// commandManager, err := NewCommandManager("../CommandDB/") +// if err != nil { +// log.Fatalf("Failed to initialize command manager: %v", err) +// } +// +// // ID로 데이터를 가져오기 (예시) +// id := "P_Collection_Kimsuky_001" +// command, exists := commandManager.GetByID(id) +// if exists { +// fmt.Printf("Command found: %+v\n", command) +// } else { +// fmt.Printf("Command with ID %s not found\n", id) +// } +//} diff --git a/Core/CommandManager_test.go b/Core/CommandManager_test.go new file mode 100644 index 0000000..b6ec3cd --- /dev/null +++ b/Core/CommandManager_test.go @@ -0,0 +1,23 @@ +package Core + +import ( + "fmt" + "testing" +) + +// CommandManager의 기본 동작을 테스트 +func TestCommandManager_LoadAndGetByID(t *testing.T) { + + cm, err := NewCommandManager() + if err != nil { + t.Fatalf("err: %s", err) + } + // ID로 CommandData 가져오기 + id := "P_Collection_Kimsuky_001" + command, exists := cm.GetByID(id) + if !exists { + t.Fatalf("Expected command with ID %s not found", id) + } + + fmt.Println(command) +} diff --git a/Core/JobManager.go b/Core/JobManager.go index 22bb214..3812780 100644 --- a/Core/JobManager.go +++ b/Core/JobManager.go @@ -1,48 +1,61 @@ package Core import ( - "time" + "fmt" + "github.com/your/repo/Model" ) -type JobData struct { - TechnicalID string `json:"technicalID"` - AgentUUID string `json:"agentUUID"` - MessageUUID string `json:"messageUUID"` - createAt time.Time -} - type JobManager struct { - dataMap map[string][]JobData + jobDB *Model.JobDB } -func NewJobManager() *JobManager { - return &JobManager{ - dataMap: make(map[string][]JobData), +// NewJobManager: JobDB와 연결하고 JobManager 생성 +func NewJobManager() (*JobManager, error) { + jobDB, err := Model.NewJobDB() + if err != nil { + return nil, err } + + return &JobManager{jobDB: jobDB}, nil } -func popFront(slice []JobData) (JobData, []JobData) { - if len(slice) > 0 { - job := slice[0] - return job, slice[1:] +// InsertData: Model의 InsertJobData 함수를 호출하여 JobData 삽입 +func (jm *JobManager) InsertData(jobData *Model.JobData) error { + err := jm.jobDB.InsertJobData(jobData) + if err != nil { + return err } - return slice[0], slice + return nil } -func (jm *JobManager) GetData(agentUUID string) (*JobData, bool) { - jobs, exists := jm.dataMap[agentUUID] - - if len(jobs) > 0 { - var job JobData - job, jm.dataMap[agentUUID] = popFront(jobs) - return &job, exists +func (jm *JobManager) popData(agentUUID string) (*Model.JobData, error, bool) { + job, err, exist := jm.getDataByAgentUUID(agentUUID) + if err != nil { + return nil, err, exist + } + if exist == false { + return nil, fmt.Errorf("Error! NoRecord"), exist } - return &JobData{}, exists + return job, nil, exist + } -func (jm *JobManager) insertData(jobData JobData) bool { - jm.dataMap[jobData.AgentUUID] = append(jm.dataMap[jobData.AgentUUID], jobData) +// GetDataByAgentUUID: Model의 GetJobDataByAgentUUID 함수를 호출하여 JobData 조회 +func (jm *JobManager) getDataByAgentUUID(agentUUID string) (*Model.JobData, error, bool) { + job, err, exist := jm.jobDB.SelectJobDataByAgentUUID(agentUUID) + if err != nil { + return nil, err, exist + } - return true + return job, nil, exist +} + +// DeleteDataByInstructionUUID: Model의 DeleteJobDataByInstructionUUID 함수를 호출하여 JobData 삭제 +func (jm *JobManager) deleteDataByInstructionUUID(instructionUUID string) error { + err := jm.jobDB.DeleteJobDataByInstructionUUID(instructionUUID) + if err != nil { + return err + } + return nil } diff --git a/Model/JobData.go b/Model/JobData.go new file mode 100644 index 0000000..124d282 --- /dev/null +++ b/Model/JobData.go @@ -0,0 +1,100 @@ +package Model + +import ( + "database/sql" + "fmt" + "time" +) + +type JobData struct { + ProcedureID string `json:"procedureID"` + AgentUUID string `json:"agentUUID"` + InstructionUUID string `json:"instructionUUID"` + CreateAt time.Time `json:"createAt"` +} + +/** +Chatgpt 이용해서 생성 +*/ + +type JobDB struct { + db *sql.DB +} + +// NewJobDB: SQLite DB를 초기화하고 테이블을 생성하는 함수 +func NewJobDB() (*JobDB, error) { + db, err := getDBPtr() + if err != nil { + return nil, err + } + + jd := &JobDB{db: db} + err = jd.createTableIfNotExists() + if err != nil { + return nil, err + } + + return jd, nil +} + +// createTableIfNotExists: jobs 테이블이 없으면 생성 +func (jd *JobDB) createTableIfNotExists() error { + createTableSQL := ` + CREATE TABLE IF NOT EXISTS jobs ( + ProcedureID TEXT, + AgentUUID TEXT, + InstructionUUID TEXT PRIMARY KEY, + CreateAt DATETIME + );` + + _, err := jd.db.Exec(createTableSQL) + if err != nil { + return fmt.Errorf("create table failed: %w", err) + } + return nil +} + +// InsertJobData: JobData를 삽입하는 함수 +func (jd *JobDB) InsertJobData(jobData *JobData) error { + jobData.CreateAt = time.Now() + insertSQL := `INSERT INTO jobs (ProcedureID, AgentUUID, InstructionUUID, CreateAt) + VALUES (?, ?, ?, ?)` + _, err := jd.db.Exec(insertSQL, jobData.ProcedureID, jobData.AgentUUID, jobData.InstructionUUID, jobData.CreateAt) + if err != nil { + return fmt.Errorf("insert job failed: %w", err) + } + return nil +} + +// GetJobDataByAgentUUID: AgentUUID 기반으로 JobData 조회 +func (jd *JobDB) SelectJobDataByAgentUUID(agentUUID string) (*JobData, error, bool) { + selectSQL := `SELECT ProcedureID, AgentUUID, InstructionUUID, CreateAt FROM jobs WHERE AgentUUID = ?` + + rows, err := jd.db.Query(selectSQL, agentUUID) + if err != nil { + return nil, err, false + } + defer rows.Close() + if rows.Next() == false { + // 결과가 없다면, + return &JobData{}, nil, false + } + + var job *JobData = &JobData{} + err = rows.Scan(&job.ProcedureID, &job.AgentUUID, &job.InstructionUUID, &job.CreateAt) // 첫 행에만 적용 + if err != nil { + return nil, err, true + } + + return job, nil, true +} + +// DeleteJobDataByInstructionUUID: InstructionUUID 기반으로 JobData 삭제 +func (jd *JobDB) DeleteJobDataByInstructionUUID(instructionUUID string) error { + deleteSQL := `DELETE FROM jobs WHERE InstructionUUID = ?` + _, err := jd.db.Exec(deleteSQL, instructionUUID) + if err != nil { + return fmt.Errorf("delete job failed: %w", err) + } + return nil +} diff --git a/go.mod b/go.mod index 570ba99..dff45d1 100644 --- a/go.mod +++ b/go.mod @@ -37,5 +37,6 @@ require ( golang.org/x/sys v0.24.0 // indirect golang.org/x/text v0.16.0 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index c4744a3..88a055b 100644 --- a/go.sum +++ b/go.sum @@ -96,5 +96,7 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 54ccc0f3173776dc767426f654222c52a7cd8ff6 Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Tue, 10 Sep 2024 20:06:41 +0900 Subject: [PATCH 13/26] =?UTF-8?q?HTTPS-53=20<=20instructionManager=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/CommandDispatcher.go | 2 +- ...ommandManager.go => InstructionManager.go} | 57 ++++++++++++------- ...ger_test.go => InstructionManager_test.go} | 8 +-- app.go | 39 +++++++++++++ go.mod | 5 +- go.sum | 12 ++++ 6 files changed, 95 insertions(+), 28 deletions(-) rename Core/{CommandManager.go => InstructionManager.go} (51%) rename Core/{CommandManager_test.go => InstructionManager_test.go} (58%) diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index 3a06493..e31d4de 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -233,7 +233,7 @@ func postLogOfProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { } if exist == true { // job 이 있다면 - cmdMgr, err := NewCommandManager() + cmdMgr, err := NewInstructionManager() if err != nil { return nil, err } diff --git a/Core/CommandManager.go b/Core/InstructionManager.go similarity index 51% rename from Core/CommandManager.go rename to Core/InstructionManager.go index 9e79c84..945d999 100644 --- a/Core/CommandManager.go +++ b/Core/InstructionManager.go @@ -13,8 +13,8 @@ import ( ChatGpt 로 생성한 코드임 */ -// CommandData는 주어진 YAML 데이터를 저장할 구조체입니다. -type CommandData struct { +// InstructionData는 주어진 YAML 데이터를 저장할 구조체입니다. +type InstructionData struct { ID string `yaml:"id"` MITREID string `yaml:"MITRE_ID"` Description string `yaml:"Description"` @@ -24,8 +24,8 @@ type CommandData struct { Cleanup string `yaml:"cleanup"` } -// ToBytes는 CommandData 구조체를 YAML 바이트 슬라이스로 변환하는 함수입니다. -func (cd *CommandData) ToBytes() ([]byte, error) { +// ToBytes는 InstructionData 구조체를 YAML 바이트 슬라이스로 변환하는 함수입니다. +func (cd *InstructionData) ToBytes() ([]byte, error) { // YAML로 직렬화 data, err := yaml.Marshal(cd) if err != nil { @@ -34,14 +34,14 @@ func (cd *CommandData) ToBytes() ([]byte, error) { return data, nil } -// CommandManager는 모든 CommandData를 관리하는 구조체입니다. -type CommandManager struct { - commands map[string]CommandData +// InstructionManager는 모든 InstructionData를 관리하는 구조체입니다. +type InstructionManager struct { + commands map[string]InstructionData } -// NewCommandManager는 CommandManager를 초기화하고 YAML 파일들을 읽어들입니다. -func NewCommandManager() (*CommandManager, error) { - cm := &CommandManager{commands: make(map[string]CommandData)} +// NewInstructionManager는 InstructionManager를 초기화하고 YAML 파일들을 읽어들입니다. +func NewInstructionManager() (*InstructionManager, error) { + cm := &InstructionManager{commands: make(map[string]InstructionData)} err := cm.loadCommands() if err != nil { @@ -51,15 +51,15 @@ func NewCommandManager() (*CommandManager, error) { return cm, nil } -// loadCommands는 주어진 경로에서 모든 YAML 파일을 읽어들여 CommandData로 변환합니다. -func (cm *CommandManager) loadCommands() error { +// loadCommands는 주어진 경로에서 모든 YAML 파일을 읽어들여 InstructionData로 변환합니다. +func (cm *InstructionManager) loadCommands() error { // 디렉토리 내의 모든 YAML 파일을 찾습니다. files, err := filepath.Glob(filepath.Join("../CommandDB/", "*.yaml")) if err != nil { return fmt.Errorf("failed to read directory: %w", err) } - // 각 파일을 읽고 CommandData로 변환 + // 각 파일을 읽고 InstructionData로 변환 for _, file := range files { err := cm.loadCommandFile(file) if err != nil { @@ -70,8 +70,8 @@ func (cm *CommandManager) loadCommands() error { return nil } -// loadCommandFile은 하나의 YAML 파일을 읽어 CommandData로 변환하고 저장합니다. -func (cm *CommandManager) loadCommandFile(filepath string) error { +// loadCommandFile은 하나의 YAML 파일을 읽어 InstructionData로 변환하고 저장합니다. +func (cm *InstructionManager) loadCommandFile(filepath string) error { file, err := os.Open(filepath) if err != nil { return fmt.Errorf("failed to open file: %w", err) @@ -84,8 +84,8 @@ func (cm *CommandManager) loadCommandFile(filepath string) error { return fmt.Errorf("failed to read file: %w", err) } - // YAML 데이터를 CommandData 구조체로 변환 - var command CommandData + // YAML 데이터를 InstructionData 구조체로 변환 + var command InstructionData err = yaml.Unmarshal(data, &command) if err != nil { return fmt.Errorf("failed to unmarshal yaml: %w", err) @@ -97,8 +97,8 @@ func (cm *CommandManager) loadCommandFile(filepath string) error { return nil } -// GetByID는 주어진 ID에 해당하는 CommandData를 반환합니다. -func (cm *CommandManager) GetByID(id string) (*CommandData, bool) { +// GetByID는 주어진 ID에 해당하는 InstructionData를 반환합니다. +func (cm *InstructionManager) GetByID(id string) (*InstructionData, bool) { command, exists := cm.commands[id] if !exists { return nil, false @@ -106,16 +106,29 @@ func (cm *CommandManager) GetByID(id string) (*CommandData, bool) { return &command, true } +//// Insert는 새로운 InstructionData를 삽입하는 함수입니다. +//// 이미 동일한 ID가 존재하면 false를 반환하고, 성공적으로 삽입되면 true를 반환합니다. +//func (cm *InstructionManager) Insert(command InstructionData) bool { +// // ID가 이미 존재하는지 확인 +// if _, exists := cm.commands[command.ID]; exists { +// return false // 이미 존재하면 삽입하지 않고 false 반환 +// } +// +// // 맵에 새 InstructionData 삽입 +// cm.commands[command.ID] = command +// return true +//} + //func main() { -// // ../CommandDB/ 디렉토리에 있는 모든 YAML 파일을 읽어 CommandManager를 초기화합니다. -// commandManager, err := NewCommandManager("../CommandDB/") +// // ../CommandDB/ 디렉토리에 있는 모든 YAML 파일을 읽어 InstructionManager를 초기화합니다. +// InstructionManager, err := NewInstructionManager("../CommandDB/") // if err != nil { // log.Fatalf("Failed to initialize command manager: %v", err) // } // // // ID로 데이터를 가져오기 (예시) // id := "P_Collection_Kimsuky_001" -// command, exists := commandManager.GetByID(id) +// command, exists := InstructionManager.GetByID(id) // if exists { // fmt.Printf("Command found: %+v\n", command) // } else { diff --git a/Core/CommandManager_test.go b/Core/InstructionManager_test.go similarity index 58% rename from Core/CommandManager_test.go rename to Core/InstructionManager_test.go index b6ec3cd..2e8654f 100644 --- a/Core/CommandManager_test.go +++ b/Core/InstructionManager_test.go @@ -5,14 +5,14 @@ import ( "testing" ) -// CommandManager의 기본 동작을 테스트 -func TestCommandManager_LoadAndGetByID(t *testing.T) { +// InstructionManager의 기본 동작을 테스트 +func TestInstructionManager_LoadAndGetByID(t *testing.T) { - cm, err := NewCommandManager() + cm, err := NewInstructionManager() if err != nil { t.Fatalf("err: %s", err) } - // ID로 CommandData 가져오기 + // ID로 InstructionData 가져오기 id := "P_Collection_Kimsuky_001" command, exists := cm.GetByID(id) if !exists { diff --git a/app.go b/app.go index 4430a55..1a68e08 100644 --- a/app.go +++ b/app.go @@ -2,11 +2,15 @@ package main import ( "bytes" + "encoding/json" "fmt" "github.com/HTTPs-omma/HSProtocol/HSProtocol" "github.com/gofiber/fiber/v3" "github.com/joho/godotenv" + "github.com/your/repo/Core" + "github.com/your/repo/Model" "net" + "time" ) var testCommand string = "dir /" @@ -87,6 +91,12 @@ func handleTCPConnection(conn net.Conn) { } } +type InstructionD struct { + agentUUID string `json:"agentUUID"` + procedureID string `json:"procedureID"` + instructionUUID string `json:"instructionUUID"` +} + // HTTP 서버 함수 (Fiber 사용) func HTTPServer() { app := fiber.New() @@ -96,6 +106,7 @@ func HTTPServer() { HSMgr := HSProtocol.NewHSProtocolManager() hs, err := HSMgr.Parsing(req) if err != nil { + ctx.Status(404) return fmt.Errorf("Error parsing:", err) } @@ -104,6 +115,34 @@ func HTTPServer() { return nil }) + // POST 요청을 처리하는 핸들러 + app.Post("/postInstruction", func(ctx fiber.Ctx) error { + data := ctx.Body() + InstD := &InstructionD{} + err := json.Unmarshal(data, &InstD) + if err != nil { + fmt.Println("Error marshaling to JSON:", err) + ctx.Status(404) + return err + } + jobMgr, err := Core.NewJobManager() + if err != nil { + return err + } + + jobMgr.InsertData(&Model.JobData{ + InstD.procedureID, + InstD.agentUUID, + InstD.instructionUUID, + time.Now(), + }) + + ctx.Status(200) + return ctx.JSON(fiber.Map{ + "status": true, + }) + }) + fmt.Println("HTTP server listening on port 80") err := app.Listen(":80") if err != nil { diff --git a/go.mod b/go.mod index dff45d1..408f3b1 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/andybalholm/brotli v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-ole/go-ole v1.2.6 // indirect + github.com/gofiber/fiber/v2 v2.52.5 // indirect github.com/gofiber/utils/v2 v2.0.0-beta.6 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect @@ -23,8 +24,10 @@ require ( github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.16 // indirect github.com/montanaflynn/stats v0.7.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.55.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect @@ -34,7 +37,7 @@ require ( github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect golang.org/x/crypto v0.24.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.24.0 // indirect + golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.16.0 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 88a055b..ededbc3 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= +github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg= github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY= github.com/gofiber/utils/v2 v2.0.0-beta.6 h1:ED62bOmpRXdgviPlfTmf0Q+AXzhaTUAFtdWjgx+XkYI= @@ -34,10 +36,18 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -81,6 +91,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= From d5275dbf00ee83102a60491fb6ab4a532c4e6644 Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Wed, 11 Sep 2024 14:57:51 +0900 Subject: [PATCH 14/26] =?UTF-8?q?HTTPS-53=20<=20getPacket=20=EB=9D=BC?= =?UTF-8?q?=EC=9A=B0=ED=84=B0=20=EA=B5=AC=ED=98=84,=20PostInstruction=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=84=B0=20=EA=B5=AC=ED=98=84=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/Managed-Server.iml | 10 +++- Core/CommandDispatcher.go | 2 +- Model/AgentStatus.go | 6 ++- Model/ApplicationDB.go | 2 + Model/JobData.go | 97 +++++++++++++++++++++++++++------ Model/OperationLog.go | 44 ++++++++------- Model/OperationLog_test.go | 19 +++---- Model/SystemInfoDB.go | 4 +- Model/db.go | 2 + app.go | 108 ++++++++++++++++++++++++++++++++----- go.mod | 17 +++--- go.sum | 47 +++++++++------- 12 files changed, 269 insertions(+), 89 deletions(-) diff --git a/.idea/Managed-Server.iml b/.idea/Managed-Server.iml index 5e764c4..d356d82 100644 --- a/.idea/Managed-Server.iml +++ b/.idea/Managed-Server.iml @@ -1,9 +1,17 @@ + + + + + - + + + + \ No newline at end of file diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index e31d4de..902b106 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -22,7 +22,7 @@ const ( POST_LOG_OF_PROCEDURE = 0b0000000111 ) -func (cd *CommandDispatcher) action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { +func (cd *CommandDispatcher) Action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // hsMgr := HSProtocol.NewHSProtocolManager() switch hs.Command { diff --git a/Model/AgentStatus.go b/Model/AgentStatus.go index e633bb9..b35ed40 100644 --- a/Model/AgentStatus.go +++ b/Model/AgentStatus.go @@ -91,7 +91,6 @@ func BinaryToProtocol(i uint8) Protocol { } } - type AgentStatusDB struct { dbName string } @@ -107,7 +106,9 @@ type AgentStatusRecord struct { // NewAgentStatusDB creates a new instance of AgentStatusDB with the default table name. func NewAgentStatusDB() *AgentStatusDB { - return &AgentStatusDB{dbName: "AgentStatus"} + db := &AgentStatusDB{dbName: "AgentStatus"} + db.CreateTable() + return db } // CreateTable creates the AgentStatus table if it does not exist. @@ -188,6 +189,7 @@ func (s *AgentStatusDB) SelectRecords() ([]AgentStatusRecord, error) { query := fmt.Sprintf(`SELECT id, uuid, status, protocol, createAt, updateAt FROM %s`, s.dbName) rows, err := db.Query(query) + defer rows.Close() if err != nil { return nil, err } diff --git a/Model/ApplicationDB.go b/Model/ApplicationDB.go index bcbc91e..e1f59b1 100644 --- a/Model/ApplicationDB.go +++ b/Model/ApplicationDB.go @@ -12,6 +12,7 @@ type ApplicationDB struct { func NewApplicationDB() (metaTable *ApplicationDB) { appDB := &ApplicationDB{"Application"} + appDB.createTable() return appDB } @@ -249,6 +250,7 @@ func (s *ApplicationDB) SelectAllRecords() ([]DapplicationDB, error) { query := fmt.Sprintf(`SELECT * FROM %s `, s.dbName) row, err := db.Query(query) + defer row.Close() if err != nil { return nil, err } diff --git a/Model/JobData.go b/Model/JobData.go index 124d282..0ef69c8 100644 --- a/Model/JobData.go +++ b/Model/JobData.go @@ -1,7 +1,6 @@ package Model import ( - "database/sql" "fmt" "time" ) @@ -18,48 +17,53 @@ Chatgpt 이용해서 생성 */ type JobDB struct { - db *sql.DB + dbName string } // NewJobDB: SQLite DB를 초기화하고 테이블을 생성하는 함수 func NewJobDB() (*JobDB, error) { - db, err := getDBPtr() + jd := &JobDB{dbName: "jobs"} + err := jd.createTableIfNotExists() if err != nil { return nil, err } - - jd := &JobDB{db: db} - err = jd.createTableIfNotExists() - if err != nil { - return nil, err - } - return jd, nil } // createTableIfNotExists: jobs 테이블이 없으면 생성 func (jd *JobDB) createTableIfNotExists() error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + createTableSQL := ` CREATE TABLE IF NOT EXISTS jobs ( ProcedureID TEXT, AgentUUID TEXT, - InstructionUUID TEXT PRIMARY KEY, + InstructionUUID TEXT, CreateAt DATETIME );` - _, err := jd.db.Exec(createTableSQL) + _, err = db.Exec(createTableSQL) if err != nil { return fmt.Errorf("create table failed: %w", err) } return nil } -// InsertJobData: JobData를 삽입하는 함수 func (jd *JobDB) InsertJobData(jobData *JobData) error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() jobData.CreateAt = time.Now() insertSQL := `INSERT INTO jobs (ProcedureID, AgentUUID, InstructionUUID, CreateAt) VALUES (?, ?, ?, ?)` - _, err := jd.db.Exec(insertSQL, jobData.ProcedureID, jobData.AgentUUID, jobData.InstructionUUID, jobData.CreateAt) + _, err = db.Exec(insertSQL, jobData.ProcedureID, jobData.AgentUUID, jobData.InstructionUUID, jobData.CreateAt) + fmt.Println(jobData) if err != nil { return fmt.Errorf("insert job failed: %w", err) } @@ -68,9 +72,14 @@ func (jd *JobDB) InsertJobData(jobData *JobData) error { // GetJobDataByAgentUUID: AgentUUID 기반으로 JobData 조회 func (jd *JobDB) SelectJobDataByAgentUUID(agentUUID string) (*JobData, error, bool) { - selectSQL := `SELECT ProcedureID, AgentUUID, InstructionUUID, CreateAt FROM jobs WHERE AgentUUID = ?` + db, err := getDBPtr() + if err != nil { + return nil, err, false + } + defer db.Close() - rows, err := jd.db.Query(selectSQL, agentUUID) + selectSQL := `SELECT ProcedureID, AgentUUID, InstructionUUID, CreateAt FROM jobs WHERE AgentUUID = ?` + rows, err := db.Query(selectSQL, agentUUID) if err != nil { return nil, err, false } @@ -89,10 +98,64 @@ func (jd *JobDB) SelectJobDataByAgentUUID(agentUUID string) (*JobData, error, bo return job, nil, true } +func (jd *JobDB) SelectAllJobData() ([]JobData, error) { + + db, err := getDBPtr() + if err != nil { + return nil, err + } + defer db.Close() + + selectSQL := `SELECT ProcedureID, AgentUUID, InstructionUUID, CreateAt FROM jobs` + + rows, err := db.Query(selectSQL) + defer rows.Close() + if err != nil { + return nil, err + } + if rows.Next() == false { + return []JobData{}, nil + } + + jobs := []JobData{} + for rows.Next() == true { + var job *JobData = &JobData{} + err = rows.Scan(&job.ProcedureID, &job.AgentUUID, &job.InstructionUUID, &job.CreateAt) // 첫 행에만 적용 + if err != nil { + return nil, err + } + jobs = append(jobs, *job) + } + + return jobs, nil +} + // DeleteJobDataByInstructionUUID: InstructionUUID 기반으로 JobData 삭제 func (jd *JobDB) DeleteJobDataByInstructionUUID(instructionUUID string) error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + deleteSQL := `DELETE FROM jobs WHERE InstructionUUID = ?` - _, err := jd.db.Exec(deleteSQL, instructionUUID) + _, err = db.Exec(deleteSQL, instructionUUID) + if err != nil { + return fmt.Errorf("delete job failed: %w", err) + } + return nil +} + +// DeleteJobDataByInstructionUUID: InstructionUUID 기반으로 JobData 삭제 +func (jd *JobDB) DeleteAllJobData() error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + deleteSQL := `DELETE FROM jobs` + _, err = db.Exec(deleteSQL) if err != nil { return fmt.Errorf("delete job failed: %w", err) } diff --git a/Model/OperationLog.go b/Model/OperationLog.go index e5d8728..5993bcb 100644 --- a/Model/OperationLog.go +++ b/Model/OperationLog.go @@ -14,37 +14,34 @@ import ( 검토자 : 허남정 */ - // OperationLogDocument 구조체 정의 type OperationLogDocument struct { - ID primitive.ObjectID `bson:"_id,omitempty"` - AgentUUID string `bson:"agentUUID"` - ProcedureID string `bson:"procedureID"` - InstructionUUID string `bson:"instructionUUID"` - ConductAt time.Time `bson:"conductAt"` - ExitCode int `bson:"exitCode"` - Log string `bson:"log"` - Command string `bson:"command"` // Command 필드로 변경 + ID primitive.ObjectID `bson:"_id,omitempty"` + AgentUUID string `bson:"agentUUID"` + ProcedureID string `bson:"procedureID"` + InstructionUUID string `bson:"instructionUUID"` + ConductAt time.Time `bson:"conductAt"` + ExitCode int `bson:"exitCode"` + Log string `bson:"log"` + Command string `bson:"command"` // Command 필드로 변경 } -// OperationLogDB는 CRUD 작업을 수행하는 구조체입니다. type OperationLogDB struct { Collection *mongo.Collection } -// NewOperationLogDB는 OperationLogDB 인스턴스를 생성합니다. func NewOperationLogDB() (*OperationLogDB, error) { db, err := getCollectionPtr() if err != nil { return nil, err } - return &OperationLogDB{ + OpDB := &OperationLogDB{ Collection: db.Collection("execLog"), - }, nil + } + return OpDB, nil } -// Create는 새로운 OperationLogDocument 문서를 MongoDB에 삽입합니다. -func (repo *OperationLogDB) insertDocument(log OperationLogDocument) (*mongo.InsertOneResult, error) { +func (repo *OperationLogDB) InsertDocument(log OperationLogDocument) (*mongo.InsertOneResult, error) { // Command 필드를 기본값으로 설정 (필요에 따라 변경) result, err := repo.Collection.InsertOne(context.TODO(), log) fmt.Println(log) @@ -56,8 +53,7 @@ func (repo *OperationLogDB) insertDocument(log OperationLogDocument) (*mongo.Ins return result, nil } -// Read는 OperationLogDocument 문서를 조회합니다. -func (repo *OperationLogDB) selectDocumentById(id string) (*OperationLogDocument, error) { +func (repo *OperationLogDB) SelectDocumentById(id string) (*OperationLogDocument, error) { var OperationLogDocument OperationLogDocument filter := bson.M{"instructionUUID": id} @@ -69,7 +65,18 @@ func (repo *OperationLogDB) selectDocumentById(id string) (*OperationLogDocument return &OperationLogDocument, nil } -// Update는 OperationLogDocument 문서를 수정합니다. +func (repo *OperationLogDB) SelectAllDocuments() (*OperationLogDocument, error) { + var OperationLogDocument OperationLogDocument + filter := bson.M{} + + err := repo.Collection.FindOne(context.TODO(), filter).Decode(&OperationLogDocument) + if err != nil { + return nil, err + } + + return &OperationLogDocument, nil +} + func (repo *OperationLogDB) UpdateDocumentByInstID(id string, updateData bson.M) (*mongo.UpdateResult, error) { filter := bson.M{"instructionUUID": id} update := bson.M{ @@ -85,7 +92,6 @@ func (repo *OperationLogDB) UpdateDocumentByInstID(id string, updateData bson.M) return result, nil } -// Delete는 OperationLogDocument 문서를 삭제합니다. func (repo *OperationLogDB) DeleteDocumentByInstID(id string) (*mongo.DeleteResult, error) { filter := bson.M{"instructionUUID": id} diff --git a/Model/OperationLog_test.go b/Model/OperationLog_test.go index 651122f..87cc02f 100644 --- a/Model/OperationLog_test.go +++ b/Model/OperationLog_test.go @@ -16,13 +16,13 @@ func TestInsertDocument(t *testing.T) { { name: "Insert valid document", log: OperationLogDocument{ - AgentUUID: "agent-123", - ProcedureID: "tech-456", + AgentUUID: "agent-123", + ProcedureID: "tech-456", InstructionUUID: "msg-789", - ConductAt: time.Now(), - ExitCode: 0, - Log: "Test log message", - Command: "Test command", + ConductAt: time.Now(), + ExitCode: 0, + Log: "Test log message", + Command: "Test command", }, }, } @@ -42,7 +42,7 @@ func TestInsertDocument(t *testing.T) { } // insertDocument 호출 - result, err := db.insertDocument(tt.log) + result, err := db.InsertDocument(tt.log) if err != nil { t.Errorf("insertDocument() 에러: %v", err) } @@ -54,7 +54,7 @@ func TestInsertDocument(t *testing.T) { t.Logf("삽입된 문서 ID: %v", result.InsertedID) } - log, err := db.selectDocumentById(tt.log.InstructionUUID) + log, err := db.SelectDocumentById(tt.log.InstructionUUID) if err != nil { t.Fatalf("select 오류") } @@ -74,7 +74,6 @@ func TestInsertDocument(t *testing.T) { // t.Fatalf("update 오류") //} - rst, err := db.DeleteDocumentByInstID(tt.log.InstructionUUID) if err != nil { t.Errorf("DeleteDocumentByInstID() 에러: %v", err) @@ -87,8 +86,6 @@ func TestInsertDocument(t *testing.T) { //t.Logf("삭제된 문서 ID: %v", rst.) } - - }) } } diff --git a/Model/SystemInfoDB.go b/Model/SystemInfoDB.go index e9d69d9..86220c8 100644 --- a/Model/SystemInfoDB.go +++ b/Model/SystemInfoDB.go @@ -27,6 +27,7 @@ type DsystemInfoDB struct { func NewSystemInfoDB() *SystemInfoDB { sysDB := &SystemInfoDB{"SystemInfo"} + sysDB.CreateTable() return sysDB } @@ -103,7 +104,7 @@ func (s *SystemInfoDB) InsertRecord(data *DsystemInfoDB) error { OsName, OsVersion, Family, Architecture, KernelVersion, BootTime) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, s.dbName) stmt, err := db.Prepare(query) - fmt.Println(query) + defer stmt.Close() if err != nil { return err @@ -177,6 +178,7 @@ func (s *SystemInfoDB) SelectRecords() ([]DsystemInfoDB, error) { query := fmt.Sprintf(`SELECT * FROM %s`, s.dbName) row, err := db.Query(query) + defer row.Close() if err != nil { return nil, err } diff --git a/Model/db.go b/Model/db.go index 1d33863..002e54b 100644 --- a/Model/db.go +++ b/Model/db.go @@ -3,6 +3,7 @@ package Model import ( "database/sql" "errors" + _ "modernc.org/sqlite" "time" ) @@ -15,6 +16,7 @@ db파일 : https://medium.com/@SlackBeck/golang-database-sql-패키지-삽질기 */ func getDBPtr() (*sql.DB, error) { dbPath := "file:db.db?cache=shared" + //dbPath := "db.db" db, err := sql.Open("sqlite", dbPath) if err != nil { diff --git a/app.go b/app.go index 1a68e08..eadaa53 100644 --- a/app.go +++ b/app.go @@ -2,7 +2,6 @@ package main import ( "bytes" - "encoding/json" "fmt" "github.com/HTTPs-omma/HSProtocol/HSProtocol" "github.com/gofiber/fiber/v3" @@ -92,9 +91,9 @@ func handleTCPConnection(conn net.Conn) { } type InstructionD struct { - agentUUID string `json:"agentUUID"` - procedureID string `json:"procedureID"` - instructionUUID string `json:"instructionUUID"` + ProcedureID string `json:"procedureID"` + AgentUUID string `json:"agentUUID"` + InstructionUUID string `json:"instructionUUID"` } // HTTP 서버 함수 (Fiber 사용) @@ -111,15 +110,16 @@ func HTTPServer() { } fmt.Println("hs.uuid : ", hs.UUID) + dipt := Core.CommandDispatcher{} + dipt.Action(hs) return nil }) - // POST 요청을 처리하는 핸들러 app.Post("/postInstruction", func(ctx fiber.Ctx) error { - data := ctx.Body() - InstD := &InstructionD{} - err := json.Unmarshal(data, &InstD) + //https://github.com/gofiber/fiber/issues/2958 + InstD := new(InstructionD) + err := ctx.Bind().JSON(InstD) if err != nil { fmt.Println("Error marshaling to JSON:", err) ctx.Status(404) @@ -129,13 +129,18 @@ func HTTPServer() { if err != nil { return err } + fmt.Println("test : ", InstD.ProcedureID, InstD.AgentUUID, InstD.InstructionUUID) - jobMgr.InsertData(&Model.JobData{ - InstD.procedureID, - InstD.agentUUID, - InstD.instructionUUID, + err = jobMgr.InsertData(&Model.JobData{ + InstD.ProcedureID, + InstD.AgentUUID, + InstD.InstructionUUID, time.Now(), }) + if err != nil { + fmt.Println("Error inserting data:", err) + return fmt.Errorf("Error inserting data into job manager: %v", err) + } ctx.Status(200) return ctx.JSON(fiber.Map{ @@ -143,6 +148,85 @@ func HTTPServer() { }) }) + app.Get("/view/agentStatus", func(ctx fiber.Ctx) error { + //data := ctx.Body() + db := Model.NewAgentStatusDB() + datas, err := db.SelectRecords() + if err != nil { + fmt.Println("Error selecting records:", err) + ctx.Status(404) + return nil + } + ctx.Status(200) + return ctx.JSON(datas) + }) + + app.Get("/view/ApplicationDB", func(ctx fiber.Ctx) error { + fmt.Println("ApplicationDB loging") + db := Model.NewApplicationDB() + datas, err := db.SelectAllRecords() + if err != nil { + fmt.Println("Error selecting records:", err) + ctx.Status(404) + return nil + } + ctx.Status(200) + return ctx.JSON(datas) + }) + + app.Get("/view/OperationLogDB", func(ctx fiber.Ctx) error { + db, _ := Model.NewOperationLogDB() + datas, err := db.SelectAllDocuments() + if err != nil { + ctx.Status(404) + return nil + } + ctx.Status(200) + return ctx.JSON(datas) + }) + + app.Get("/view/SystemInfoDB", func(ctx fiber.Ctx) error { + //data := ctx.Body() + db := Model.NewSystemInfoDB() + datas, err := db.SelectRecords() + if err != nil { + fmt.Println("Error selecting records:", err) + ctx.Status(404) + return nil + } + ctx.Status(200) + return ctx.JSON(datas) + }) + + app.Get("/view/JobDataDB", func(ctx fiber.Ctx) error { + db, err := Model.NewJobDB() + if err != nil { + return err + } + datas, err := db.SelectAllJobData() + if err != nil { + fmt.Println("Error selecting records:", err) + ctx.Status(404) + return nil + } + ctx.Status(200) + return ctx.JSON(datas) + }) + + app.Get("/deleted/DeletedJobDataDB", func(ctx fiber.Ctx) error { + db, err := Model.NewJobDB() + if err != nil { + return err + } + err = db.DeleteAllJobData() + if err != nil { + fmt.Println("Error Deleted records:", err) + ctx.Status(404) + return nil + } + return nil + }) + fmt.Println("HTTP server listening on port 80") err := app.Listen(":80") if err != nil { diff --git a/go.mod b/go.mod index 408f3b1..a1240c4 100644 --- a/go.mod +++ b/go.mod @@ -7,27 +7,28 @@ require ( github.com/gofiber/fiber/v3 v3.0.0-beta.3 github.com/joho/godotenv v1.5.1 github.com/stretchr/testify v1.9.0 - github.com/yusufpapurcu/wmi v1.2.4 go.mongodb.org/mongo-driver v1.16.1 + gopkg.in/yaml.v2 v2.4.0 + modernc.org/sqlite v1.33.0 ) require ( github.com/andybalholm/brotli v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect - github.com/gofiber/fiber/v2 v2.52.5 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/gofiber/utils/v2 v2.0.0-beta.6 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/kr/pretty v0.1.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect github.com/montanaflynn/stats v0.7.1 // indirect + github.com/ncruces/go-strftime v0.1.9 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/rivo/uniseg v0.4.7 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.55.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect @@ -40,6 +41,10 @@ require ( golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.16.0 // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect + modernc.org/mathutil v1.6.0 // indirect + modernc.org/memory v1.8.0 // indirect + modernc.org/strutil v1.2.0 // indirect + modernc.org/token v1.1.0 // indirect ) diff --git a/go.sum b/go.sum index ededbc3..04aff18 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,3 @@ -github.com/HTTPs-omma/HSProtocol v1.0.2 h1:YV2MDAljka+Th3RsL649Bz2ZU+KUhLerS4GcI/z++9c= -github.com/HTTPs-omma/HSProtocol v1.0.2/go.mod h1:IvJQe3yhvo0qunuPoB499HuGBGE3QS0MWU8OYRuvAus= github.com/HTTPs-omma/HSProtocol v1.0.3 h1:8OZxA4Vc2H1QsTLPYQ8B7++B5r0M8g6Gaom/IZ2JHvg= github.com/HTTPs-omma/HSProtocol v1.0.3/go.mod h1:IvJQe3yhvo0qunuPoB499HuGBGE3QS0MWU8OYRuvAus= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= @@ -7,10 +5,8 @@ github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer5 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= -github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo= -github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg= github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY= github.com/gofiber/utils/v2 v2.0.0-beta.6 h1:ED62bOmpRXdgviPlfTmf0Q+AXzhaTUAFtdWjgx+XkYI= @@ -19,8 +15,12 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= +github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= @@ -36,18 +36,14 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= +github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -65,8 +61,6 @@ github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gi github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= -github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -74,6 +68,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -82,15 +78,12 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -104,6 +97,8 @@ golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= @@ -112,3 +107,17 @@ gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= +modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= +modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= +modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= +modernc.org/sqlite v1.33.0 h1:WWkA/T2G17okiLGgKAj4/RMIvgyMT19yQ038160IeYk= +modernc.org/sqlite v1.33.0/go.mod h1:9uQ9hF/pCZoYZK73D/ud5Z7cIRIILSZI8NdIemVMTX8= +modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= +modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= +modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= From 0bbb85ce566e38872874a055876d44ef9b4ba0bd Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Fri, 13 Sep 2024 17:31:08 +0900 Subject: [PATCH 15/26] =?UTF-8?q?HTTPS-53=20<=20swagger=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8B=80=20=EC=9C=84=ED=95=9C=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?=EB=B9=8C=EB=93=9C=EC=97=85=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/inspectionProfiles/Project_Default.xml | 12 ++ .idea/misc.xml | 6 + docs/docs.go | 36 ++++ docs/swagger.json | 7 + docs/swagger.yaml | 4 + go.mod | 96 ++++++++- go.sum | 211 +++++++++++++++++++ app.go => main.go | 35 ++- 8 files changed, 397 insertions(+), 10 deletions(-) create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/misc.xml create mode 100644 docs/docs.go create mode 100644 docs/swagger.json create mode 100644 docs/swagger.yaml rename app.go => main.go (87%) diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..69a1ce5 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0dbbef0 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/docs/docs.go b/docs/docs.go new file mode 100644 index 0000000..6676994 --- /dev/null +++ b/docs/docs.go @@ -0,0 +1,36 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": {} +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/docs/swagger.json b/docs/swagger.json new file mode 100644 index 0000000..ec416cd --- /dev/null +++ b/docs/swagger.json @@ -0,0 +1,7 @@ +{ + "swagger": "2.0", + "info": { + "contact": {} + }, + "paths": {} +} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml new file mode 100644 index 0000000..b64379c --- /dev/null +++ b/docs/swagger.yaml @@ -0,0 +1,4 @@ +info: + contact: {} +paths: {} +swagger: "2.0" diff --git a/go.mod b/go.mod index a1240c4..0288496 100644 --- a/go.mod +++ b/go.mod @@ -13,38 +13,120 @@ require ( ) require ( + dario.cat/mergo v1.0.1 // indirect + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.3.0 // indirect + github.com/Masterminds/sprig/v3 v3.3.0 // indirect + github.com/PuerkitoBio/purell v1.2.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/andybalholm/brotli v1.1.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/bytedance/sonic v1.12.2 // indirect + github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gabriel-vasile/mimetype v1.4.5 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.10.0 // indirect + github.com/go-openapi/analysis v0.23.0 // indirect + github.com/go-openapi/errors v0.22.0 // indirect + github.com/go-openapi/inflect v0.21.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/loads v0.22.0 // indirect + github.com/go-openapi/runtime v0.28.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/strfmt v0.23.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/validate v0.24.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.22.1 // indirect + github.com/go-swagger/go-swagger v0.31.0 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/gofiber/utils/v2 v2.0.0-beta.6 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/handlers v1.5.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/huandu/xstrings v1.5.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/jessevdk/go-flags v1.6.1 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect - github.com/kr/pretty v0.1.0 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.7.1 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/oklog/ulid v1.3.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/rogpeppe/go-internal v1.12.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/shopspring/decimal v1.4.0 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.7.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.19.0 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + github.com/swaggo/files v1.0.1 // indirect + github.com/swaggo/gin-swagger v1.6.0 // indirect + github.com/swaggo/swag v1.16.3 // indirect + github.com/toqueteos/webbrowser v1.2.0 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect + github.com/urfave/cli/v2 v2.27.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.55.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect - golang.org/x/crypto v0.24.0 // indirect - golang.org/x/sync v0.7.0 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/arch v0.10.0 // indirect + golang.org/x/crypto v0.27.0 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect + golang.org/x/mod v0.21.0 // indirect + golang.org/x/net v0.29.0 // indirect + golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.16.0 // indirect - gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + golang.org/x/text v0.18.0 // indirect + golang.org/x/tools v0.25.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.8.0 // indirect modernc.org/strutil v1.2.0 // indirect modernc.org/token v1.1.0 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 04aff18..663c30b 100644 --- a/go.sum +++ b/go.sum @@ -1,51 +1,225 @@ +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/HTTPs-omma/HSProtocol v1.0.3 h1:8OZxA4Vc2H1QsTLPYQ8B7++B5r0M8g6Gaom/IZ2JHvg= github.com/HTTPs-omma/HSProtocol v1.0.3/go.mod h1:IvJQe3yhvo0qunuPoB499HuGBGE3QS0MWU8OYRuvAus= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= +github.com/PuerkitoBio/purell v1.2.1 h1:QsZ4TjvwiMpat6gBCBxEQI0rcS9ehtkKtSpiUnd9N28= +github.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.12.2 h1:oaMFuRTpMHYLpCntGca65YWt5ny+wAceDERTkT2L9lg= +github.com/bytedance/sonic v1.12.2/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= +github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= +github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= +github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= +github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= +github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= +github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= +github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= +github.com/go-openapi/inflect v0.21.0 h1:FoBjBTQEcbg2cJUWX6uwL9OyIW8eqc9k4KhN4lfbeYk= +github.com/go-openapi/inflect v0.21.0/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= +github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= +github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= +github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= +github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= +github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= +github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-swagger/go-swagger v0.31.0 h1:H8eOYQnY2u7vNKWDNykv2xJP3pBhRG/R+SOCAmKrLlc= +github.com/go-swagger/go-swagger v0.31.0/go.mod h1:WSigRRWEig8zV6t6Sm8Y+EmUjlzA/HoaZJ5edupq7po= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg= github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY= github.com/gofiber/utils/v2 v2.0.0-beta.6 h1:ED62bOmpRXdgviPlfTmf0Q+AXzhaTUAFtdWjgx+XkYI= github.com/gofiber/utils/v2 v2.0.0-beta.6/go.mod h1:3Kz8Px3jInKFvqxDzDeoSygwEOO+3uyubTmUa6PqY+0= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4= +github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= +github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= +github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= +github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= +github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= +github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= +github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8= +github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= @@ -58,53 +232,86 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.10.0 h1:S3huipmSclq3PJMNe76NGwkBR504WFkQ5dhzWzP8ZW8= +golang.org/x/arch v0.10.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= @@ -121,3 +328,7 @@ modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/app.go b/main.go similarity index 87% rename from app.go rename to main.go index eadaa53..3884d88 100644 --- a/app.go +++ b/main.go @@ -4,8 +4,11 @@ import ( "bytes" "fmt" "github.com/HTTPs-omma/HSProtocol/HSProtocol" + "github.com/gin-gonic/gin" "github.com/gofiber/fiber/v3" "github.com/joho/godotenv" + swaggerFiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" "github.com/your/repo/Core" "github.com/your/repo/Model" "net" @@ -27,12 +30,23 @@ func main() { // tcp go TCPServer() - // udp - ////go UDPServer() - // HTTP HTTPServer() + r := gin.Default() + + // API 엔드포인트 + r.GET("/api/v1/docs", HelloWorld) + + // Swagger 엔드포인트 + r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) + + r.Run(":8080") +} +func HelloWorld(c *gin.Context) { + c.JSON(200, gin.H{ + "message": "Hello World", + }) } func TCPServer() { @@ -227,9 +241,24 @@ func HTTPServer() { return nil }) + app.Get("/view/sdsa", func(ctx fiber.Ctx) error { + db, err := Model.NewJobDB() + if err != nil { + return err + } + err = db.DeleteAllJobData() + if err != nil { + fmt.Println("Error Deleted records:", err) + ctx.Status(404) + return nil + } + return nil + }) + fmt.Println("HTTP server listening on port 80") err := app.Listen(":80") if err != nil { fmt.Println("Error starting HTTP server:", err) } + } From 4145997d85533495291c7f43f4bbc29af0eca4ee Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Fri, 13 Sep 2024 21:56:38 +0900 Subject: [PATCH 16/26] HTTPS-53 < Lunch Swagger > --- PacketQueue.go | 3 - docs/docs.go | 67 +++++++++++++++-- docs/swagger.json | 62 ++++++++++++++- docs/swagger.yaml | 45 ++++++++++- go.mod | 59 +-------------- go.sum | 130 +------------------------------- main.go | 187 ++++++++-------------------------------------- router/api.go | 96 ++++++++++++++++++++++++ router/view.go | 122 ++++++++++++++++++++++++++++++ 9 files changed, 419 insertions(+), 352 deletions(-) delete mode 100644 PacketQueue.go create mode 100644 router/api.go create mode 100644 router/view.go diff --git a/PacketQueue.go b/PacketQueue.go deleted file mode 100644 index ae82798..0000000 --- a/PacketQueue.go +++ /dev/null @@ -1,3 +0,0 @@ -package main - -// 해당 코드는 Chatgpt 로 작성되었습니다. diff --git a/docs/docs.go b/docs/docs.go index 6676994..fde17b8 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -9,22 +9,75 @@ const docTemplate = `{ "info": { "description": "{{escape .Description}}", "title": "{{.Title}}", - "contact": {}, + "termsOfService": "http://managingserver.io/terms/", + "contact": { + "name": "ManagingServer API Support", + "url": "http://managingserver.io/support", + "email": "support@managingserver.io" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, "version": "{{.Version}}" }, "host": "{{.Host}}", "basePath": "{{.BasePath}}", - "paths": {} + "paths": { + "/api/postInst": { + "post": { + "description": "get struct array by ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "operationId": "get-struct-array2-by-string", + "parameters": [ + { + "type": "string", + "description": "Procedure ID (default: 'P_Collection_Kimsuky_001')", + "name": "procedureID", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Agent UUID (default: '123e4567e89b12d3a456426614174000')", + "name": "agentUUID", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Instruction UUID (default: '550e8400e29b41d4a716446655440000')", + "name": "instructionUUID", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "ok", + "schema": { + "type": "string" + } + } + } + } + } + } }` // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ - Version: "", - Host: "", - BasePath: "", + Version: "1.0", + Host: "localhost:80", + BasePath: "/", Schemes: []string{}, - Title: "", - Description: "", + Title: "ManagingServer API", + Description: "This is a sample server for the ManagingServer project.", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, LeftDelim: "{{", diff --git a/docs/swagger.json b/docs/swagger.json index ec416cd..d19af5c 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1,7 +1,65 @@ { "swagger": "2.0", "info": { - "contact": {} + "description": "This is a sample server for the ManagingServer project.", + "title": "ManagingServer API", + "termsOfService": "http://managingserver.io/terms/", + "contact": { + "name": "ManagingServer API Support", + "url": "http://managingserver.io/support", + "email": "support@managingserver.io" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + }, + "version": "1.0" }, - "paths": {} + "host": "localhost:80", + "basePath": "/", + "paths": { + "/api/postInst": { + "post": { + "description": "get struct array by ID", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "operationId": "get-struct-array2-by-string", + "parameters": [ + { + "type": "string", + "description": "Procedure ID (default: 'P_Collection_Kimsuky_001')", + "name": "procedureID", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Agent UUID (default: '123e4567e89b12d3a456426614174000')", + "name": "agentUUID", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Instruction UUID (default: '550e8400e29b41d4a716446655440000')", + "name": "instructionUUID", + "in": "query", + "required": true + } + ], + "responses": { + "200": { + "description": "ok", + "schema": { + "type": "string" + } + } + } + } + } + } } \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml index b64379c..ba561b1 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,4 +1,45 @@ +basePath: / +host: localhost:80 info: - contact: {} -paths: {} + contact: + email: support@managingserver.io + name: ManagingServer API Support + url: http://managingserver.io/support + description: This is a sample server for the ManagingServer project. + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + termsOfService: http://managingserver.io/terms/ + title: ManagingServer API + version: "1.0" +paths: + /api/postInst: + post: + consumes: + - application/json + description: get struct array by ID + operationId: get-struct-array2-by-string + parameters: + - description: 'Procedure ID (default: ''P_Collection_Kimsuky_001'')' + in: query + name: procedureID + required: true + type: string + - description: 'Agent UUID (default: ''123e4567e89b12d3a456426614174000'')' + in: query + name: agentUUID + required: true + type: string + - description: 'Instruction UUID (default: ''550e8400e29b41d4a716446655440000'')' + in: query + name: instructionUUID + required: true + type: string + produces: + - application/json + responses: + "200": + description: ok + schema: + type: string swagger: "2.0" diff --git a/go.mod b/go.mod index 0288496..94f549f 100644 --- a/go.mod +++ b/go.mod @@ -4,129 +4,78 @@ go 1.23.0 require ( github.com/HTTPs-omma/HSProtocol v1.0.3 + github.com/gin-gonic/gin v1.10.0 github.com/gofiber/fiber/v3 v3.0.0-beta.3 github.com/joho/godotenv v1.5.1 github.com/stretchr/testify v1.9.0 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.0 + github.com/swaggo/swag v1.16.3 go.mongodb.org/mongo-driver v1.16.1 gopkg.in/yaml.v2 v2.4.0 modernc.org/sqlite v1.33.0 ) require ( - dario.cat/mergo v1.0.1 // indirect github.com/KyleBanks/depth v1.2.1 // indirect - github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.3.0 // indirect - github.com/Masterminds/sprig/v3 v3.3.0 // indirect - github.com/PuerkitoBio/purell v1.2.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/andybalholm/brotli v1.1.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/bytedance/sonic v1.12.2 // indirect github.com/bytedance/sonic/loader v0.2.0 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.5 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.10.0 // indirect - github.com/go-openapi/analysis v0.23.0 // indirect - github.com/go-openapi/errors v0.22.0 // indirect - github.com/go-openapi/inflect v0.21.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/loads v0.22.0 // indirect - github.com/go-openapi/runtime v0.28.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/strfmt v0.23.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/go-openapi/validate v0.24.0 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.22.1 // indirect - github.com/go-swagger/go-swagger v0.31.0 // indirect github.com/goccy/go-json v0.10.3 // indirect github.com/gofiber/utils/v2 v2.0.0-beta.6 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/handlers v1.5.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect - github.com/huandu/xstrings v1.5.0 // indirect - github.com/imdario/mergo v0.3.16 // indirect - github.com/jessevdk/go-flags v1.6.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect - github.com/kr/pretty v0.3.1 // indirect - github.com/kr/text v0.2.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect - github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/montanaflynn/stats v0.7.1 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect - github.com/oklog/ulid v1.3.1 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sagikazarmark/locafero v0.6.0 // indirect - github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/shopspring/decimal v1.4.0 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.7.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.19.0 // indirect - github.com/subosito/gotenv v1.6.0 // indirect - github.com/swaggo/files v1.0.1 // indirect - github.com/swaggo/gin-swagger v1.6.0 // indirect - github.com/swaggo/swag v1.16.3 // indirect - github.com/toqueteos/webbrowser v1.2.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect - github.com/urfave/cli/v2 v2.27.4 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.55.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect - github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect - go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.10.0 // indirect golang.org/x/crypto v0.27.0 // indirect - golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect - golang.org/x/mod v0.21.0 // indirect golang.org/x/net v0.29.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/text v0.18.0 // indirect golang.org/x/tools v0.25.0 // indirect google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect - gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect modernc.org/mathutil v1.6.0 // indirect modernc.org/memory v1.8.0 // indirect modernc.org/strutil v1.2.0 // indirect modernc.org/token v1.1.0 // indirect - sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 663c30b..721d918 100644 --- a/go.sum +++ b/go.sum @@ -1,99 +1,56 @@ -dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= -dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/HTTPs-omma/HSProtocol v1.0.3 h1:8OZxA4Vc2H1QsTLPYQ8B7++B5r0M8g6Gaom/IZ2JHvg= github.com/HTTPs-omma/HSProtocol v1.0.3/go.mod h1:IvJQe3yhvo0qunuPoB499HuGBGE3QS0MWU8OYRuvAus= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= -github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= -github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= -github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= -github.com/PuerkitoBio/purell v1.2.1 h1:QsZ4TjvwiMpat6gBCBxEQI0rcS9ehtkKtSpiUnd9N28= -github.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= -github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.12.2 h1:oaMFuRTpMHYLpCntGca65YWt5ny+wAceDERTkT2L9lg= github.com/bytedance/sonic v1.12.2/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= -github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= +github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= -github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= -github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= -github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= -github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= -github.com/go-openapi/inflect v0.21.0 h1:FoBjBTQEcbg2cJUWX6uwL9OyIW8eqc9k4KhN4lfbeYk= -github.com/go-openapi/inflect v0.21.0/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= -github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= -github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= -github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= -github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= -github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/go-swagger/go-swagger v0.31.0 h1:H8eOYQnY2u7vNKWDNykv2xJP3pBhRG/R+SOCAmKrLlc= -github.com/go-swagger/go-swagger v0.31.0/go.mod h1:WSigRRWEig8zV6t6Sm8Y+EmUjlzA/HoaZJ5edupq7po= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg= github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY= github.com/gofiber/utils/v2 v2.0.0-beta.6 h1:ED62bOmpRXdgviPlfTmf0Q+AXzhaTUAFtdWjgx+XkYI= github.com/gofiber/utils/v2 v2.0.0-beta.6/go.mod h1:3Kz8Px3jInKFvqxDzDeoSygwEOO+3uyubTmUa6PqY+0= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -101,18 +58,8 @@ github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlG github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= -github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= -github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= -github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/jessevdk/go-flags v1.6.1 h1:Cvu5U8UGrLay1rZfv/zP7iLpSHGUZ/Ou68T0iX1bBK4= -github.com/jessevdk/go-flags v1.6.1/go.mod h1:Mk8T1hIAWpOiJiHa9rJASDK2UGWji0EuPGBnNLMooyc= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -125,19 +72,12 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= -github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -145,12 +85,6 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= -github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -160,40 +94,15 @@ github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8 github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sagikazarmark/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= -github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= -github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= -github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= -github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= -github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= -github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= -github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= -github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -204,22 +113,16 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= -github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= -github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= -github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8= -github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= @@ -232,29 +135,18 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= -github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.10.0 h1:S3huipmSclq3PJMNe76NGwkBR504WFkQ5dhzWzP8ZW8= golang.org/x/arch v0.10.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -265,8 +157,6 @@ golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -287,28 +177,19 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= -gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -329,6 +210,3 @@ modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0 modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/main.go b/main.go index 3884d88..ce53aae 100644 --- a/main.go +++ b/main.go @@ -6,15 +6,27 @@ import ( "github.com/HTTPs-omma/HSProtocol/HSProtocol" "github.com/gin-gonic/gin" "github.com/gofiber/fiber/v3" + "github.com/gofiber/fiber/v3/middleware/cors" "github.com/joho/godotenv" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" - "github.com/your/repo/Core" - "github.com/your/repo/Model" + _ "github.com/your/repo/docs" + "github.com/your/repo/router" "net" - "time" ) +// @title Swagger Example API +// @version 1.0 +// @description This is a sample server Petstore server. +// @termsOfService http://swagger.io/terms/ +// @contact.name API Support +// @contact.url http://www.swagger.io/support +// @contact.email support@swagger.io +// @license.name Apache 2.0 +// @license.url http://www.apache.org/licenses/LICENSE-2.0.html +// @host petstore.swagger.io +// @BasePath / +// @Path api var testCommand string = "dir /" func main() { @@ -30,23 +42,23 @@ func main() { // tcp go TCPServer() + // Swagger + go Swagger() + // HTTP HTTPServer() - r := gin.Default() +} - // API 엔드포인트 - r.GET("/api/v1/docs", HelloWorld) +// https://zzihyeon.tistory.com/76 +func Swagger() { + r := gin.Default() // Swagger 엔드포인트 r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) r.Run(":8080") -} -func HelloWorld(c *gin.Context) { - c.JSON(200, gin.H{ - "message": "Hello World", - }) + } func TCPServer() { @@ -104,156 +116,17 @@ func handleTCPConnection(conn net.Conn) { } } -type InstructionD struct { - ProcedureID string `json:"procedureID"` - AgentUUID string `json:"agentUUID"` - InstructionUUID string `json:"instructionUUID"` -} - -// HTTP 서버 함수 (Fiber 사용) func HTTPServer() { app := fiber.New() - app.Post("/getPacket", func(ctx fiber.Ctx) error { - req := ctx.Body() - HSMgr := HSProtocol.NewHSProtocolManager() - hs, err := HSMgr.Parsing(req) - if err != nil { - ctx.Status(404) - return fmt.Errorf("Error parsing:", err) - } - - fmt.Println("hs.uuid : ", hs.UUID) - dipt := Core.CommandDispatcher{} - dipt.Action(hs) - - return nil - }) - - app.Post("/postInstruction", func(ctx fiber.Ctx) error { - //https://github.com/gofiber/fiber/issues/2958 - InstD := new(InstructionD) - err := ctx.Bind().JSON(InstD) - if err != nil { - fmt.Println("Error marshaling to JSON:", err) - ctx.Status(404) - return err - } - jobMgr, err := Core.NewJobManager() - if err != nil { - return err - } - fmt.Println("test : ", InstD.ProcedureID, InstD.AgentUUID, InstD.InstructionUUID) - - err = jobMgr.InsertData(&Model.JobData{ - InstD.ProcedureID, - InstD.AgentUUID, - InstD.InstructionUUID, - time.Now(), - }) - if err != nil { - fmt.Println("Error inserting data:", err) - return fmt.Errorf("Error inserting data into job manager: %v", err) - } - - ctx.Status(200) - return ctx.JSON(fiber.Map{ - "status": true, - }) - }) - - app.Get("/view/agentStatus", func(ctx fiber.Ctx) error { - //data := ctx.Body() - db := Model.NewAgentStatusDB() - datas, err := db.SelectRecords() - if err != nil { - fmt.Println("Error selecting records:", err) - ctx.Status(404) - return nil - } - ctx.Status(200) - return ctx.JSON(datas) - }) - - app.Get("/view/ApplicationDB", func(ctx fiber.Ctx) error { - fmt.Println("ApplicationDB loging") - db := Model.NewApplicationDB() - datas, err := db.SelectAllRecords() - if err != nil { - fmt.Println("Error selecting records:", err) - ctx.Status(404) - return nil - } - ctx.Status(200) - return ctx.JSON(datas) - }) - - app.Get("/view/OperationLogDB", func(ctx fiber.Ctx) error { - db, _ := Model.NewOperationLogDB() - datas, err := db.SelectAllDocuments() - if err != nil { - ctx.Status(404) - return nil - } - ctx.Status(200) - return ctx.JSON(datas) - }) - - app.Get("/view/SystemInfoDB", func(ctx fiber.Ctx) error { - //data := ctx.Body() - db := Model.NewSystemInfoDB() - datas, err := db.SelectRecords() - if err != nil { - fmt.Println("Error selecting records:", err) - ctx.Status(404) - return nil - } - ctx.Status(200) - return ctx.JSON(datas) - }) - - app.Get("/view/JobDataDB", func(ctx fiber.Ctx) error { - db, err := Model.NewJobDB() - if err != nil { - return err - } - datas, err := db.SelectAllJobData() - if err != nil { - fmt.Println("Error selecting records:", err) - ctx.Status(404) - return nil - } - ctx.Status(200) - return ctx.JSON(datas) - }) - - app.Get("/deleted/DeletedJobDataDB", func(ctx fiber.Ctx) error { - db, err := Model.NewJobDB() - if err != nil { - return err - } - err = db.DeleteAllJobData() - if err != nil { - fmt.Println("Error Deleted records:", err) - ctx.Status(404) - return nil - } - return nil - }) + // 효과적인 Cors 에러 해결 + app.Use(cors.New(cors.Config{ + AllowCredentials: true, + AllowOriginsFunc: func(origin string) bool { return true }, + })) - app.Get("/view/sdsa", func(ctx fiber.Ctx) error { - db, err := Model.NewJobDB() - if err != nil { - return err - } - err = db.DeleteAllJobData() - if err != nil { - fmt.Println("Error Deleted records:", err) - ctx.Status(404) - return nil - } - return nil - }) + router.SetupAPIRoutes(app) + router.SetupViewRoutes(app) fmt.Println("HTTP server listening on port 80") err := app.Listen(":80") diff --git a/router/api.go b/router/api.go new file mode 100644 index 0000000..aa04685 --- /dev/null +++ b/router/api.go @@ -0,0 +1,96 @@ +package router + +import ( + "fmt" + "github.com/HTTPs-omma/HSProtocol/HSProtocol" + "github.com/gofiber/fiber/v3" + "github.com/your/repo/Core" + "github.com/your/repo/Model" + _ "github.com/your/repo/docs" + "time" +) + +type InstructionD struct { + ProcedureID string `json:"procedureID"` + AgentUUID string `json:"agentUUID"` + InstructionUUID string `json:"instructionUUID"` +} + +// @title ManagingServer API +// @version 1.0 +// @description This is a sample server for the ManagingServer project. +// @termsOfService http://managingserver.io/terms/ +// @contact.name ManagingServer API Support +// @contact.url http://managingserver.io/support +// @contact.email support@managingserver.io +// @license.name Apache 2.0 +// @license.url http://www.apache.org/licenses/LICENSE-2.0.html +// @host localhost:80 +// @BasePath / +// @Path /api + +func SetupAPIRoutes(app *fiber.App) { + + app.Post("/api/checkInstReq", checkInstReq) + app.Post("/api/postInst", postInst) +} + +func checkInstReq(ctx fiber.Ctx) error { + req := ctx.Body() + HSMgr := HSProtocol.NewHSProtocolManager() + hs, err := HSMgr.Parsing(req) + if err != nil { + ctx.Status(404) + return fmt.Errorf("Error parsing:", err) + } + + fmt.Println("hs.uuid : ", hs.UUID) + dipt := Core.CommandDispatcher{} + dipt.Action(hs) + + return nil +} + +// postInst example +// +// @Description get struct array by ID +// @ID get-struct-array2-by-string +// @Accept json +// @Produce json +// @Param procedureID query string true "Procedure ID (default: 'P_Collection_Kimsuky_001')" +// @Param agentUUID query string true "Agent UUID (default: '123e4567e89b12d3a456426614174000')" +// @Param instructionUUID query string true "Instruction UUID (default: '550e8400e29b41d4a716446655440000')" +// @Success 200 {string} string "ok" +// @Default {"procedureID": "How to implement a Library", "agentUUID": "2023-09-15T10:00:00Z", "instructionUUID" : :"550e8400-e29b-41d4-a716-446655440000"} +// @Router /api/postInst [post] +func postInst(ctx fiber.Ctx) error { + // https://github.com/gofiber/fiber/issues/2958 + InstD := new(InstructionD) + err := ctx.Bind().JSON(InstD) + if err != nil { + fmt.Println("Error marshaling to JSON:", err) + ctx.Status(404) + return ctx.Send([]byte(err.Error())) + } + jobMgr, err := Core.NewJobManager() + if err != nil { + return ctx.Send([]byte(err.Error())) + } + fmt.Println("test : ", InstD.ProcedureID, InstD.AgentUUID, InstD.InstructionUUID) + + err = jobMgr.InsertData(&Model.JobData{ + InstD.ProcedureID, + InstD.AgentUUID, + InstD.InstructionUUID, + time.Now(), + }) + if err != nil { + fmt.Println("Error inserting data:", err) + return fmt.Errorf("Error inserting data into job manager: %v", err) + } + + ctx.Status(200) + return ctx.JSON(fiber.Map{ + "status": true, + }) +} diff --git a/router/view.go b/router/view.go new file mode 100644 index 0000000..40a81bf --- /dev/null +++ b/router/view.go @@ -0,0 +1,122 @@ +package router + +import ( + "fmt" + "github.com/gofiber/fiber/v3" + "github.com/your/repo/Model" +) + +func SetupViewRoutes(app *fiber.App) { + // /view/OperationLogDB 라우트 정의 + app.Get("/view/OperationLogDB", func(ctx fiber.Ctx) error { + db, err := Model.NewOperationLogDB() + if err != nil { + ctx.Status(500) + return ctx.SendString("Failed to connect to the database") + } + + // 모든 문서 조회 + datas, err := db.SelectAllDocuments() + if err != nil { + ctx.Status(404) + return ctx.SendString("Documents not found") + } + + // 성공 시 JSON으로 응답 + ctx.Status(200) + return ctx.JSON(datas) + }) + + app.Get("/view/agentStatus", func(ctx fiber.Ctx) error { + //data := ctx.Body() + db := Model.NewAgentStatusDB() + datas, err := db.SelectRecords() + if err != nil { + fmt.Println("Error selecting records:", err) + ctx.Status(404) + return nil + } + ctx.Status(200) + return ctx.JSON(datas) + }) + + app.Get("/view/ApplicationDB", func(ctx fiber.Ctx) error { + fmt.Println("ApplicationDB loging") + db := Model.NewApplicationDB() + datas, err := db.SelectAllRecords() + if err != nil { + fmt.Println("Error selecting records:", err) + ctx.Status(404) + return nil + } + ctx.Status(200) + return ctx.JSON(datas) + }) + + app.Get("/view/OperationLogDB", func(ctx fiber.Ctx) error { + db, _ := Model.NewOperationLogDB() + datas, err := db.SelectAllDocuments() + if err != nil { + ctx.Status(404) + return nil + } + ctx.Status(200) + return ctx.JSON(datas) + }) + + app.Get("/view/SystemInfoDB", func(ctx fiber.Ctx) error { + //data := ctx.Body() + db := Model.NewSystemInfoDB() + datas, err := db.SelectRecords() + if err != nil { + fmt.Println("Error selecting records:", err) + ctx.Status(404) + return nil + } + ctx.Status(200) + return ctx.JSON(datas) + }) + + app.Get("/view/JobDataDB", func(ctx fiber.Ctx) error { + db, err := Model.NewJobDB() + if err != nil { + return err + } + datas, err := db.SelectAllJobData() + if err != nil { + fmt.Println("Error selecting records:", err) + ctx.Status(404) + return nil + } + ctx.Status(200) + return ctx.JSON(datas) + }) + + app.Get("/deleted/DeletedJobDataDB", func(ctx fiber.Ctx) error { + db, err := Model.NewJobDB() + if err != nil { + return err + } + err = db.DeleteAllJobData() + if err != nil { + fmt.Println("Error Deleted records:", err) + ctx.Status(404) + return nil + } + return nil + }) + + app.Get("/view/sdsa", func(ctx fiber.Ctx) error { + db, err := Model.NewJobDB() + if err != nil { + return err + } + err = db.DeleteAllJobData() + if err != nil { + fmt.Println("Error Deleted records:", err) + ctx.Status(404) + return nil + } + return nil + }) +} From 63b65de18d20f64bdca8d0f7afaee1bf48d9b5d0 Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Sat, 14 Sep 2024 00:04:45 +0900 Subject: [PATCH 17/26] =?UTF-8?q?HTTPS-53=20<=20DB=20=EC=83=81=ED=83=9C=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20html=20=EC=82=AC=EC=9D=B4=ED=8A=B8=20?= =?UTF-8?q?=EC=A0=9C=EC=9E=91=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/CommandDispatcher.go | 15 +- Core/JobManager.go | 7 + Model/AgentStatus.go | 25 +++- Model/ApplicationDB.go | 25 +++- Model/OperationLog.go | 6 +- Model/SystemInfoDB.go | 27 +++- docs/docs.go | 52 +++---- docs/swagger.json | 52 +++---- docs/swagger.yaml | 40 +++--- main.go | 34 +++-- router/api.go | 41 +++--- router/view.go | 150 +++++++++++++++++++- view/html/viewdata.html | 292 ++++++++++++++++++++++++++++++++++++++ 13 files changed, 643 insertions(+), 123 deletions(-) create mode 100644 view/html/viewdata.html diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index 902b106..7f82ebc 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -47,7 +47,10 @@ func (cd *CommandDispatcher) Action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // Command: 1 (0b0000000001) func updateHealth(hs *HSProtocol.HS) (*HSProtocol.HS, error) { - agsmd := Model.NewAgentStatusDB() + agsmd, err := Model.NewAgentStatusDB() + if err != nil { + return nil, err + } rst, err := agsmd.ExistRecord() if err != nil { return nil, err @@ -108,7 +111,10 @@ func updateHealth(hs *HSProtocol.HS) (*HSProtocol.HS, error) { func updateProtocol(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // protocolID := binary.BigEndian.Uint32(hs.Data) - agsmd := Model.NewAgentStatusDB() + agsmd, err := Model.NewAgentStatusDB() + if err != nil { + return nil, err + } rst, err := agsmd.ExistRecord() if err != nil { return nil, err @@ -147,7 +153,10 @@ func updateProtocol(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // Command: 3 (0b0000000011) func postSystemInfo(hs *HSProtocol.HS) (*HSProtocol.HS, error) { - sysDB := Model.NewSystemInfoDB() + sysDB, err := Model.NewSystemInfoDB() + if err != nil { + return nil, err + } Dsys, err := sysDB.Unmarshal(hs.Data) if err != nil { return nil, err diff --git a/Core/JobManager.go b/Core/JobManager.go index 3812780..7ff915f 100644 --- a/Core/JobManager.go +++ b/Core/JobManager.go @@ -21,6 +21,13 @@ func NewJobManager() (*JobManager, error) { // InsertData: Model의 InsertJobData 함수를 호출하여 JobData 삽입 func (jm *JobManager) InsertData(jobData *Model.JobData) error { + if len(jobData.AgentUUID) != 32 { + return fmt.Errorf("AgentUUID is not 32 characters") + } + if len(jobData.InstructionUUID) != 32 { + return fmt.Errorf("InstrwuctionUUID is not 32 characters") + } + err := jm.jobDB.InsertJobData(jobData) if err != nil { return err diff --git a/Model/AgentStatus.go b/Model/AgentStatus.go index b35ed40..562b533 100644 --- a/Model/AgentStatus.go +++ b/Model/AgentStatus.go @@ -105,10 +105,13 @@ type AgentStatusRecord struct { } // NewAgentStatusDB creates a new instance of AgentStatusDB with the default table name. -func NewAgentStatusDB() *AgentStatusDB { +func NewAgentStatusDB() (*AgentStatusDB, error) { db := &AgentStatusDB{dbName: "AgentStatus"} - db.CreateTable() - return db + err := db.CreateTable() + if err != nil { + return nil, err + } + return db, nil } // CreateTable creates the AgentStatus table if it does not exist. @@ -242,6 +245,22 @@ func (s *AgentStatusDB) DeleteRecord(uuid string) error { return nil } +func (s *AgentStatusDB) DeleteAllRecord() error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`DELETE FROM %s`) + _, err = db.Exec(query) + if err != nil { + return err + } + + return nil +} + // ExistRecord checks if at least one record exists in the AgentStatus table. func (s *AgentStatusDB) ExistRecord() (bool, error) { db, err := getDBPtr() diff --git a/Model/ApplicationDB.go b/Model/ApplicationDB.go index e1f59b1..cf8175c 100644 --- a/Model/ApplicationDB.go +++ b/Model/ApplicationDB.go @@ -10,10 +10,13 @@ type ApplicationDB struct { dbName string } -func NewApplicationDB() (metaTable *ApplicationDB) { +func NewApplicationDB() (*ApplicationDB, error) { appDB := &ApplicationDB{"Application"} - appDB.createTable() - return appDB + err := appDB.createTable() + if err != nil { + return nil, err + } + return appDB, nil } type DapplicationDB struct { @@ -241,6 +244,22 @@ func (s *ApplicationDB) DeleteByPackageCode(packageCode string) error { return nil } +func (s *ApplicationDB) DeleteAllRecords() error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`DELETE FROM %s WHERE`) + _, err = db.Exec(query) + if err != nil { + return err + } + + return nil +} + func (s *ApplicationDB) SelectAllRecords() ([]DapplicationDB, error) { db, err := getDBPtr() if err != nil { diff --git a/Model/OperationLog.go b/Model/OperationLog.go index 5993bcb..0f69f6e 100644 --- a/Model/OperationLog.go +++ b/Model/OperationLog.go @@ -92,10 +92,10 @@ func (repo *OperationLogDB) UpdateDocumentByInstID(id string, updateData bson.M) return result, nil } -func (repo *OperationLogDB) DeleteDocumentByInstID(id string) (*mongo.DeleteResult, error) { - filter := bson.M{"instructionUUID": id} +func (repo *OperationLogDB) DeleteAllDocument() (*mongo.DeleteResult, error) { + filter := bson.M{} - result, err := repo.Collection.DeleteOne(context.TODO(), filter) + result, err := repo.Collection.DeleteMany(context.TODO(), filter) if err != nil { return nil, err } diff --git a/Model/SystemInfoDB.go b/Model/SystemInfoDB.go index 86220c8..0322173 100644 --- a/Model/SystemInfoDB.go +++ b/Model/SystemInfoDB.go @@ -25,10 +25,13 @@ type DsystemInfoDB struct { UpdatedAt time.Time `json:"updated_at"` } -func NewSystemInfoDB() *SystemInfoDB { +func NewSystemInfoDB() (*SystemInfoDB, error) { sysDB := &SystemInfoDB{"SystemInfo"} - sysDB.CreateTable() - return sysDB + err := sysDB.CreateTable() + if err != nil { + return nil, err + } + return sysDB, nil } func (s *SystemInfoDB) CreateTable() error { @@ -153,7 +156,7 @@ func (s *SystemInfoDB) UpdateRecord(data *DsystemInfoDB) error { return nil } -func (s *SystemInfoDB) DeleteRecord(uuid string) error { +func (s *SystemInfoDB) DeleteRecordByUUID(uuid string) error { db, err := getDBPtr() if err != nil { return err @@ -169,6 +172,22 @@ func (s *SystemInfoDB) DeleteRecord(uuid string) error { return nil } +func (s *SystemInfoDB) DeleteAllRecord() error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`DELETE FROM %s WHERE`) + _, err = db.Exec(query) + if err != nil { + return err + } + + return nil +} + func (s *SystemInfoDB) SelectRecords() ([]DsystemInfoDB, error) { db, err := getDBPtr() if err != nil { diff --git a/docs/docs.go b/docs/docs.go index fde17b8..7372b39 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -36,34 +36,36 @@ const docTemplate = `{ "operationId": "get-struct-array2-by-string", "parameters": [ { - "type": "string", - "description": "Procedure ID (default: 'P_Collection_Kimsuky_001')", - "name": "procedureID", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Agent UUID (default: '123e4567e89b12d3a456426614174000')", - "name": "agentUUID", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Instruction UUID (default: '550e8400e29b41d4a716446655440000')", - "name": "instructionUUID", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", + "description": "request job", + "name": "loginUserRequest", + "in": "body", + "required": true, "schema": { - "type": "string" + "$ref": "#/definitions/router.InstructionD" } } + ], + "responses": {} + } + } + }, + "definitions": { + "router.InstructionD": { + "type": "object", + "properties": { + "agentUUID": { + "description": "example: Test", + "type": "string", + "default": "c3cb84233416497694569d759a8a13e7" + }, + "instructionUUID": { + "type": "string", + "default": "32a2833486414af9bc4596caef585538" + }, + "procedureID": { + "description": "example: Test", + "type": "string", + "default": "P_Collection_Kimsuky_001" } } } diff --git a/docs/swagger.json b/docs/swagger.json index d19af5c..78ad96a 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -30,34 +30,36 @@ "operationId": "get-struct-array2-by-string", "parameters": [ { - "type": "string", - "description": "Procedure ID (default: 'P_Collection_Kimsuky_001')", - "name": "procedureID", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Agent UUID (default: '123e4567e89b12d3a456426614174000')", - "name": "agentUUID", - "in": "query", - "required": true - }, - { - "type": "string", - "description": "Instruction UUID (default: '550e8400e29b41d4a716446655440000')", - "name": "instructionUUID", - "in": "query", - "required": true - } - ], - "responses": { - "200": { - "description": "ok", + "description": "request job", + "name": "loginUserRequest", + "in": "body", + "required": true, "schema": { - "type": "string" + "$ref": "#/definitions/router.InstructionD" } } + ], + "responses": {} + } + } + }, + "definitions": { + "router.InstructionD": { + "type": "object", + "properties": { + "agentUUID": { + "description": "example: Test", + "type": "string", + "default": "c3cb84233416497694569d759a8a13e7" + }, + "instructionUUID": { + "type": "string", + "default": "32a2833486414af9bc4596caef585538" + }, + "procedureID": { + "description": "example: Test", + "type": "string", + "default": "P_Collection_Kimsuky_001" } } } diff --git a/docs/swagger.yaml b/docs/swagger.yaml index ba561b1..0c8edca 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1,4 +1,19 @@ basePath: / +definitions: + router.InstructionD: + properties: + agentUUID: + default: c3cb84233416497694569d759a8a13e7 + description: 'example: Test' + type: string + instructionUUID: + default: 32a2833486414af9bc4596caef585538 + type: string + procedureID: + default: P_Collection_Kimsuky_001 + description: 'example: Test' + type: string + type: object host: localhost:80 info: contact: @@ -20,26 +35,13 @@ paths: description: get struct array by ID operationId: get-struct-array2-by-string parameters: - - description: 'Procedure ID (default: ''P_Collection_Kimsuky_001'')' - in: query - name: procedureID - required: true - type: string - - description: 'Agent UUID (default: ''123e4567e89b12d3a456426614174000'')' - in: query - name: agentUUID - required: true - type: string - - description: 'Instruction UUID (default: ''550e8400e29b41d4a716446655440000'')' - in: query - name: instructionUUID + - description: request job + in: body + name: loginUserRequest required: true - type: string + schema: + $ref: '#/definitions/router.InstructionD' produces: - application/json - responses: - "200": - description: ok - schema: - type: string + responses: {} swagger: "2.0" diff --git a/main.go b/main.go index ce53aae..6b9d2ab 100644 --- a/main.go +++ b/main.go @@ -13,20 +13,21 @@ import ( _ "github.com/your/repo/docs" "github.com/your/repo/router" "net" + "os" ) -// @title Swagger Example API -// @version 1.0 -// @description This is a sample server Petstore server. -// @termsOfService http://swagger.io/terms/ -// @contact.name API Support -// @contact.url http://www.swagger.io/support -// @contact.email support@swagger.io -// @license.name Apache 2.0 -// @license.url http://www.apache.org/licenses/LICENSE-2.0.html -// @host petstore.swagger.io -// @BasePath / -// @Path api +// @title Swagger Example API +// @version 1.0 +// @description This is a sample server Petstore server. +// @termsOfService http://swagger.io/terms/ +// @contact.name API Support +// @contact.url http://www.swagger.io/support +// @contact.email support@swagger.io +// @license.name Apache 2.0 +// @license.url http://www.apache.org/licenses/LICENSE-2.0.html +// @host petstore.swagger.io +// @BasePath / +// @Path api var testCommand string = "dir /" func main() { @@ -118,6 +119,15 @@ func handleTCPConnection(conn net.Conn) { func HTTPServer() { app := fiber.New() + app.Get("/view/db", func(c fiber.Ctx) error { + // HTML 파일을 읽어서 응답으로 반환 + htmlData, err := os.ReadFile("./view/html/viewdata.html") + if err != nil { + return c.Status(500).SendString("Error loading page") + } + c.Set("Content-Type", "text/html") + return c.Send(htmlData) + }) // 효과적인 Cors 에러 해결 app.Use(cors.New(cors.Config{ diff --git a/router/api.go b/router/api.go index aa04685..790a86f 100644 --- a/router/api.go +++ b/router/api.go @@ -10,25 +10,27 @@ import ( "time" ) +// swagger:parameters Request type InstructionD struct { - ProcedureID string `json:"procedureID"` - AgentUUID string `json:"agentUUID"` - InstructionUUID string `json:"instructionUUID"` + // example: Test + ProcedureID string `json:"procedureID" default:"P_Collection_Kimsuky_001"` + // example: Test + AgentUUID string `json:"agentUUID" default:"c3cb84233416497694569d759a8a13e7"` + InstructionUUID string `json:"instructionUUID" default:"32a2833486414af9bc4596caef585538"` } -// @title ManagingServer API -// @version 1.0 -// @description This is a sample server for the ManagingServer project. -// @termsOfService http://managingserver.io/terms/ -// @contact.name ManagingServer API Support -// @contact.url http://managingserver.io/support -// @contact.email support@managingserver.io -// @license.name Apache 2.0 -// @license.url http://www.apache.org/licenses/LICENSE-2.0.html -// @host localhost:80 -// @BasePath / -// @Path /api - +// @title ManagingServer API +// @version 1.0 +// @description This is a sample server for the ManagingServer project. +// @termsOfService http://managingserver.io/terms/ +// @contact.name ManagingServer API Support +// @contact.url http://managingserver.io/support +// @contact.email support@managingserver.io +// @license.name Apache 2.0 +// @license.url http://www.apache.org/licenses/LICENSE-2.0.html +// @host localhost:80 +// @BasePath / +// @Path /api func SetupAPIRoutes(app *fiber.App) { app.Post("/api/checkInstReq", checkInstReq) @@ -57,11 +59,8 @@ func checkInstReq(ctx fiber.Ctx) error { // @ID get-struct-array2-by-string // @Accept json // @Produce json -// @Param procedureID query string true "Procedure ID (default: 'P_Collection_Kimsuky_001')" -// @Param agentUUID query string true "Agent UUID (default: '123e4567e89b12d3a456426614174000')" -// @Param instructionUUID query string true "Instruction UUID (default: '550e8400e29b41d4a716446655440000')" -// @Success 200 {string} string "ok" -// @Default {"procedureID": "How to implement a Library", "agentUUID": "2023-09-15T10:00:00Z", "instructionUUID" : :"550e8400-e29b-41d4-a716-446655440000"} +// @Param loginUserRequest body InstructionD true "request job" +// @Default {"procedureID": "P_Collection_Kimsuky_001", "agentUUID": "2023-09-15T10:00:00Z", "instructionUUID" : :"550e8400-e29b-41d4-a716-446655440000"} // @Router /api/postInst [post] func postInst(ctx fiber.Ctx) error { // https://github.com/gofiber/fiber/issues/2958 diff --git a/router/view.go b/router/view.go index 40a81bf..de9f8f9 100644 --- a/router/view.go +++ b/router/view.go @@ -6,7 +6,85 @@ import ( "github.com/your/repo/Model" ) +// 통합 구조체 정의 +type CombinedData struct { + OperationLog Model.OperationLogDocument `json:"operation_log"` + AgentStatus []Model.AgentStatusRecord `json:"agent_status"` + Application []Model.DapplicationDB `json:"application"` + JobData []Model.JobData `json:"job_data"` + SystemInfo []Model.DsystemInfoDB `json:"system_info"` +} + func SetupViewRoutes(app *fiber.App) { + app.Get("/combined-data", func(ctx fiber.Ctx) error { + dbOperationLog, err := Model.NewOperationLogDB() + if err != nil { + ctx.Status(404) + return ctx.SendString("Error : " + err.Error()) + } + // 모든 문서 조회 + dataOL, err := dbOperationLog.SelectAllDocuments() + if err != nil { + ctx.Status(404) + return ctx.SendString("Error : " + err.Error()) + } + + dbAgentStatus, err := Model.NewAgentStatusDB() + if err != nil { + ctx.Status(404) + return ctx.SendString("Error : " + err.Error()) + } + dataAS, err := dbAgentStatus.SelectRecords() + if err != nil { + fmt.Println("Error selecting records:", err) + ctx.Status(404) + return ctx.SendString("Error : " + err.Error()) + } + + appdb, err := Model.NewApplicationDB() + if err != nil { + return err + } + dataAPP, err := appdb.SelectAllRecords() + if err != nil { + fmt.Println("Error selecting records:", err) + ctx.Status(404) + return ctx.SendString("Error : " + err.Error()) + } + + dbJob, err := Model.NewJobDB() + if err != nil { + return err + } + dataJD, err := dbJob.SelectAllJobData() + if err != nil { + fmt.Println("Error selecting records:", err) + ctx.Status(404) + return ctx.SendString("Error : " + err.Error()) + } + + dbSysInfo, err := Model.NewSystemInfoDB() + if err != nil { + return err + } + dataSys, err := dbSysInfo.SelectRecords() + if err != nil { + fmt.Println("Error selecting records:", err) + ctx.Status(404) + return ctx.SendString("Error : " + err.Error()) + } + + combined := CombinedData{ + OperationLog: *dataOL, + AgentStatus: dataAS, + Application: dataAPP, + JobData: dataJD, + SystemInfo: dataSys, + } + + return ctx.JSON(combined) + }) + // /view/OperationLogDB 라우트 정의 app.Get("/view/OperationLogDB", func(ctx fiber.Ctx) error { db, err := Model.NewOperationLogDB() @@ -29,7 +107,7 @@ func SetupViewRoutes(app *fiber.App) { app.Get("/view/agentStatus", func(ctx fiber.Ctx) error { //data := ctx.Body() - db := Model.NewAgentStatusDB() + db, err := Model.NewAgentStatusDB() datas, err := db.SelectRecords() if err != nil { fmt.Println("Error selecting records:", err) @@ -42,7 +120,10 @@ func SetupViewRoutes(app *fiber.App) { app.Get("/view/ApplicationDB", func(ctx fiber.Ctx) error { fmt.Println("ApplicationDB loging") - db := Model.NewApplicationDB() + db, err := Model.NewApplicationDB() + if err != nil { + return err + } datas, err := db.SelectAllRecords() if err != nil { fmt.Println("Error selecting records:", err) @@ -66,7 +147,10 @@ func SetupViewRoutes(app *fiber.App) { app.Get("/view/SystemInfoDB", func(ctx fiber.Ctx) error { //data := ctx.Body() - db := Model.NewSystemInfoDB() + db, err := Model.NewSystemInfoDB() + if err != nil { + return err + } datas, err := db.SelectRecords() if err != nil { fmt.Println("Error selecting records:", err) @@ -92,7 +176,7 @@ func SetupViewRoutes(app *fiber.App) { return ctx.JSON(datas) }) - app.Get("/deleted/DeletedJobDataDB", func(ctx fiber.Ctx) error { + app.Get("/view/sdsa", func(ctx fiber.Ctx) error { db, err := Model.NewJobDB() if err != nil { return err @@ -106,7 +190,7 @@ func SetupViewRoutes(app *fiber.App) { return nil }) - app.Get("/view/sdsa", func(ctx fiber.Ctx) error { + app.Get("/deleted/JobDataDB", func(ctx fiber.Ctx) error { db, err := Model.NewJobDB() if err != nil { return err @@ -119,4 +203,60 @@ func SetupViewRoutes(app *fiber.App) { } return nil }) + + app.Get("/deleted/OperationLog", func(ctx fiber.Ctx) error { + db, err := Model.NewOperationLogDB() + if err != nil { + return err + } + _, err = db.DeleteAllDocument() + if err != nil { + fmt.Println("Error Deleted records:", err) + ctx.Status(404) + return nil + } + return nil + }) + + app.Get("/deleted/SystemInfoDB", func(ctx fiber.Ctx) error { + db, err := Model.NewSystemInfoDB() + if err != nil { + return err + } + err = db.DeleteAllRecord() + if err != nil { + fmt.Println("Error Deleted records:", err) + ctx.Status(404) + return nil + } + return nil + }) + + app.Get("/deleted/ApplicationDB", func(ctx fiber.Ctx) error { + db, err := Model.NewApplicationDB() + if err != nil { + return err + } + err = db.DeleteAllRecords() + if err != nil { + fmt.Println("Error Deleted records:", err) + ctx.Status(404) + return nil + } + return nil + }) + + app.Get("/deleted/AgentStatusDB", func(ctx fiber.Ctx) error { + db, err := Model.NewAgentStatusDB() + if err != nil { + return err + } + err = db.DeleteAllRecord() + if err != nil { + fmt.Println("Error Deleted records:", err) + ctx.Status(404) + return nil + } + return nil + }) } diff --git a/view/html/viewdata.html b/view/html/viewdata.html new file mode 100644 index 0000000..945094e --- /dev/null +++ b/view/html/viewdata.html @@ -0,0 +1,292 @@ + + + + + + Combined Data + + + + +

Combined Data Tables

+ + +
+
Operation Log
+
+ + + + + + + + + + + + + + +
IDAgentUUIDProcedureIDInstructionUUIDConductAtExitCodeLogCommand
+
+ +
+ + +
+
Agent Status
+
+ + + + + + + + + + + + +
IDUUIDStatusProtocolCreatedAtUpdatedAt
+
+ +
+ + +
+
Application
+
+ + + + + + + + + + + + + + + +
IDAgentUUIDNameVersionLanguageVendorInstallDateInstallLocationDescription
+
+ +
+ + +
+
Job Data
+
+ + + + + + + + + + +
ProcedureIDAgentUUIDInstructionUUIDCreatedAt
+
+ +
+ + +
+
System Info
+
+ + + + + + + + + + + + + + + + + +
IDUUIDHostNameOsNameOsVersionFamilyArchitectureKernelVersionBootTimeCreatedAtUpdatedAt
+
+ +
+ + + + + From 656b55fe462841be85442a5929c3cd1e9df57b67 Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Wed, 18 Sep 2024 04:14:22 +0900 Subject: [PATCH 18/26] =?UTF-8?q?HTTPS-53=20<=20=EC=BB=A4=EB=B0=8B?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=ED=95=9C=EA=B1=B0=20=EB=B3=B5=EA=B5=AC....?= =?UTF-8?q?=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CommandDB | 2 +- Core/CommandDispatcher.go | 12 +-- Core/JobManager.go | 133 ++++++++++++------------ Model/AgentStatus.go | 40 +++---- Model/ApplicationDB.go | 2 +- Model/JobData.go | 64 +++++++++++- Model/OperationLog.go | 70 ++++++++++--- Model/SystemInfoDB.go | 6 +- Model/nosqldb.go | 6 ++ docs/docs.go | 16 +-- docs/swagger.json | 16 +-- docs/swagger.yaml | 16 +-- go.mod | 81 --------------- go.sum | 212 -------------------------------------- main.go | 2 +- router/api.go | 12 +-- router/view.go | 37 ++++--- view/html/viewdata.html | 13 ++- 18 files changed, 274 insertions(+), 466 deletions(-) delete mode 100644 go.mod delete mode 100644 go.sum diff --git a/CommandDB b/CommandDB index 0966d55..21c2bd9 160000 --- a/CommandDB +++ b/CommandDB @@ -1 +1 @@ -Subproject commit 0966d550f70a356a06b204d0c5e9bc01110479b5 +Subproject commit 21c2bd9a6949a2090bb810fe228fdb6ec40dc659 diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index 7f82ebc..86d9427 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -2,7 +2,7 @@ package Core import ( "fmt" - "github.com/HTTPs-omma/HSProtocol/HSProtocol" + "github.com/HTTPs-omma/HTTPsBAS-HSProtocol/HSProtocol" "github.com/your/repo/Model" ) @@ -59,7 +59,7 @@ func updateHealth(hs *HSProtocol.HS) (*HSProtocol.HS, error) { return nil, fmt.Errorf("Agent Status DB : no Records") } - records, err := agsmd.SelectRecords() + records, err := agsmd.SelectAllRecords() if err != nil { return nil, err } @@ -87,7 +87,7 @@ func updateHealth(hs *HSProtocol.HS) (*HSProtocol.HS, error) { TotalLength: hs.TotalLength, Data: []byte{}, }, nil - } else if (flag == false) && (hs.HealthStatus == uint8(Model.Waiting)) { + } else if (flag == false) && (hs.HealthStatus == uint8(Model.WAIT)) { agsmd.InsertRecord(&Model.AgentStatusRecord{ UUID: string(hs.UUID[:]), Status: Model.BinaryToAgentStatus(hs.HealthStatus), @@ -123,7 +123,7 @@ func updateProtocol(hs *HSProtocol.HS) (*HSProtocol.HS, error) { return nil, fmt.Errorf("Agent Status DB : no Records") } - records, err := agsmd.SelectRecords() + records, err := agsmd.SelectAllRecords() if err != nil { return nil, err } @@ -229,13 +229,13 @@ func getProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // Command: 7 (0b0000000111) func postLogOfProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { - jbMgr, err := NewJobManager() // stack 에 있어야겠지? + jobdb, err := Model.NewJobDB() // stack 에 있어야겠지? if err != nil { return nil, err } var agentUuid string copy(hs.UUID[:], agentUuid) - job, err, exist := jbMgr.popData(agentUuid) + job, err, exist := jobdb.PopbyAgentUUID(agentUuid) if err != nil { return nil, err diff --git a/Core/JobManager.go b/Core/JobManager.go index 7ff915f..92a8335 100644 --- a/Core/JobManager.go +++ b/Core/JobManager.go @@ -1,68 +1,69 @@ package Core -import ( - "fmt" - "github.com/your/repo/Model" -) - -type JobManager struct { - jobDB *Model.JobDB -} - -// NewJobManager: JobDB와 연결하고 JobManager 생성 -func NewJobManager() (*JobManager, error) { - jobDB, err := Model.NewJobDB() - if err != nil { - return nil, err - } - - return &JobManager{jobDB: jobDB}, nil -} - -// InsertData: Model의 InsertJobData 함수를 호출하여 JobData 삽입 -func (jm *JobManager) InsertData(jobData *Model.JobData) error { - if len(jobData.AgentUUID) != 32 { - return fmt.Errorf("AgentUUID is not 32 characters") - } - if len(jobData.InstructionUUID) != 32 { - return fmt.Errorf("InstrwuctionUUID is not 32 characters") - } - - err := jm.jobDB.InsertJobData(jobData) - if err != nil { - return err - } - return nil -} - -func (jm *JobManager) popData(agentUUID string) (*Model.JobData, error, bool) { - job, err, exist := jm.getDataByAgentUUID(agentUUID) - if err != nil { - return nil, err, exist - } - if exist == false { - return nil, fmt.Errorf("Error! NoRecord"), exist - } - - return job, nil, exist - -} - -// GetDataByAgentUUID: Model의 GetJobDataByAgentUUID 함수를 호출하여 JobData 조회 -func (jm *JobManager) getDataByAgentUUID(agentUUID string) (*Model.JobData, error, bool) { - job, err, exist := jm.jobDB.SelectJobDataByAgentUUID(agentUUID) - if err != nil { - return nil, err, exist - } - - return job, nil, exist -} - -// DeleteDataByInstructionUUID: Model의 DeleteJobDataByInstructionUUID 함수를 호출하여 JobData 삭제 -func (jm *JobManager) deleteDataByInstructionUUID(instructionUUID string) error { - err := jm.jobDB.DeleteJobDataByInstructionUUID(instructionUUID) - if err != nil { - return err - } - return nil -} +// +//import ( +// "fmt" +// "github.com/your/repo/Model" +//) +// +//type JobManager struct { +// jobDB *Model.JobDB +//} +// +//// NewJobManager: JobDB와 연결하고 JobManager 생성 +//func NewJobManager() (*JobManager, error) { +// jobDB, err := Model.NewJobDB() +// if err != nil { +// return nil, err +// } +// +// return &JobManager{jobDB: jobDB}, nil +//} +// +//// InsertData: Model의 InsertJobData 함수를 호출하여 JobData 삽입 +//func (jm *JobManager) InsertData(jobData *Model.JobData) error { +// if len(jobData.AgentUUID) != 32 { +// return fmt.Errorf("AgentUUID is not 32 characters") +// } +// if len(jobData.InstructionUUID) != 32 { +// return fmt.Errorf("InstrwuctionUUID is not 32 characters") +// } +// +// err := jm.jobDB.InsertJobData(jobData) +// if err != nil { +// return err +// } +// return nil +//} +// +//func (jm *JobManager) popData(agentUUID string) (*Model.JobData, error, bool) { +// job, err, exist := jm.getDataByAgentUUID(agentUUID) +// if err != nil { +// return nil, err, exist +// } +// if exist == false { +// return nil, fmt.Errorf("Error! NoRecord"), exist +// } +// +// return job, nil, exist +// +//} +// +//// GetDataByAgentUUID: Model의 GetJobDataByAgentUUID 함수를 호출하여 JobData 조회 +//func (jm *JobManager) getDataByAgentUUID(agentUUID string) (*Model.JobData, error, bool) { +// job, err, exist := jm.jobDB.SelectJobDataByAgentUUID(agentUUID) +// if err != nil { +// return nil, err, exist +// } +// +// return job, nil, exist +//} +// +//// DeleteDataByInstructionUUID: Model의 DeleteJobDataByInstructionUUID 함수를 호출하여 JobData 삭제 +//func (jm *JobManager) deleteDataByInstructionUUID(instructionUUID string) error { +// err := jm.jobDB.DeleteJobDataByInstructionUUID(instructionUUID) +// if err != nil { +// return err +// } +// return nil +//} diff --git a/Model/AgentStatus.go b/Model/AgentStatus.go index 562b533..2b03446 100644 --- a/Model/AgentStatus.go +++ b/Model/AgentStatus.go @@ -16,7 +16,7 @@ const ( UnknownProtocol Protocol = 0b0000 // 알 수 없는 프로토콜 ) -// Protocol을 문자열로 변환하는 메서드를 구현합니다. +// // Protocol을 문자열로 변환하는 메서드를 구현합니다. func (p Protocol) String() string { switch p { case TCP: @@ -32,28 +32,28 @@ func (p Protocol) String() string { } } -// AgentStatus 유형을 정의합니다. +// // AgentStatus 유형을 정의합니다. type AgentStatus int const ( - Waiting AgentStatus = iota // 동작 중인 상태 - Running // 대기 중인 상태 - Stopping // 정지 후 사라지기 전의 상태 - Deleted - Unknown + NEW AgentStatus = iota // 동작 중인 상태 + WAIT // 대기 중인 상태 + RUN // 정지 후 사라지기 전의 상태 + DELETED + UNKNOWN ) // AgentStatus를 문자열로 변환하는 메서드를 구현합니다. func (s AgentStatus) String() string { switch s { - case Running: + case NEW: + return "NEW" + case RUN: return "Running" - case Waiting: + case WAIT: return "Waiting" - case Stopping: - return "Stopping" - case Deleted: - return "Deleted" + case DELETED: + return "DELETED" default: return "Unknown" } @@ -63,15 +63,15 @@ func (s AgentStatus) String() string { func BinaryToAgentStatus(i uint8) AgentStatus { switch i { case 0b00: - return Waiting + return NEW case 0b01: - return Running + return WAIT case 0b10: - return Stopping + return RUN case 0b11: - return Deleted + return DELETED default: - return Unknown + return UNKNOWN } } @@ -183,7 +183,7 @@ func (s *AgentStatusDB) InsertRecord(data *AgentStatusRecord) error { } // SelectRecords retrieves all records from the AgentStatus table. -func (s *AgentStatusDB) SelectRecords() ([]AgentStatusRecord, error) { +func (s *AgentStatusDB) SelectAllRecords() ([]AgentStatusRecord, error) { db, err := getDBPtr() if err != nil { return nil, err @@ -198,7 +198,7 @@ func (s *AgentStatusDB) SelectRecords() ([]AgentStatusRecord, error) { } defer rows.Close() - var records []AgentStatusRecord + records := []AgentStatusRecord{} for rows.Next() { var record AgentStatusRecord err := rows.Scan(&record.ID, &record.UUID, &record.Status, &record.Protocol, &record.CreatedAt, &record.UpdatedAt) diff --git a/Model/ApplicationDB.go b/Model/ApplicationDB.go index cf8175c..4beb842 100644 --- a/Model/ApplicationDB.go +++ b/Model/ApplicationDB.go @@ -274,7 +274,7 @@ func (s *ApplicationDB) SelectAllRecords() ([]DapplicationDB, error) { return nil, err } - var rows []DapplicationDB + rows := []DapplicationDB{} for row.Next() { var data DapplicationDB diff --git a/Model/JobData.go b/Model/JobData.go index 0ef69c8..7ca0d1f 100644 --- a/Model/JobData.go +++ b/Model/JobData.go @@ -6,6 +6,7 @@ import ( ) type JobData struct { + Id int `json:"id"` ProcedureID string `json:"procedureID"` AgentUUID string `json:"agentUUID"` InstructionUUID string `json:"instructionUUID"` @@ -40,6 +41,7 @@ func (jd *JobDB) createTableIfNotExists() error { createTableSQL := ` CREATE TABLE IF NOT EXISTS jobs ( + id INTEGER PRIMARY KEY AUTOINCREMENT, ProcedureID TEXT, AgentUUID TEXT, InstructionUUID TEXT, @@ -78,7 +80,7 @@ func (jd *JobDB) SelectJobDataByAgentUUID(agentUUID string) (*JobData, error, bo } defer db.Close() - selectSQL := `SELECT ProcedureID, AgentUUID, InstructionUUID, CreateAt FROM jobs WHERE AgentUUID = ?` + selectSQL := `SELECT id, ProcedureID, AgentUUID, InstructionUUID, CreateAt FROM jobs WHERE AgentUUID = ?` rows, err := db.Query(selectSQL, agentUUID) if err != nil { return nil, err, false @@ -90,7 +92,7 @@ func (jd *JobDB) SelectJobDataByAgentUUID(agentUUID string) (*JobData, error, bo } var job *JobData = &JobData{} - err = rows.Scan(&job.ProcedureID, &job.AgentUUID, &job.InstructionUUID, &job.CreateAt) // 첫 행에만 적용 + err = rows.Scan(&job.ProcedureID, &job.Id, &job.AgentUUID, &job.InstructionUUID, &job.CreateAt) // 첫 행에만 적용 if err != nil { return nil, err, true } @@ -106,7 +108,7 @@ func (jd *JobDB) SelectAllJobData() ([]JobData, error) { } defer db.Close() - selectSQL := `SELECT ProcedureID, AgentUUID, InstructionUUID, CreateAt FROM jobs` + selectSQL := `SELECT id, ProcedureID, AgentUUID, InstructionUUID, CreateAt FROM jobs` rows, err := db.Query(selectSQL) defer rows.Close() @@ -118,9 +120,17 @@ func (jd *JobDB) SelectAllJobData() ([]JobData, error) { } jobs := []JobData{} + + var job_init *JobData = &JobData{} + err = rows.Scan(&job_init.Id, &job_init.ProcedureID, &job_init.AgentUUID, &job_init.InstructionUUID, &job_init.CreateAt) // 첫 행에만 적용 + if err != nil { + return nil, err + } + jobs = append(jobs, *job_init) + for rows.Next() == true { var job *JobData = &JobData{} - err = rows.Scan(&job.ProcedureID, &job.AgentUUID, &job.InstructionUUID, &job.CreateAt) // 첫 행에만 적용 + err = rows.Scan(&job.Id, &job.ProcedureID, &job.AgentUUID, &job.InstructionUUID, &job.CreateAt) // 첫 행에만 적용 if err != nil { return nil, err } @@ -130,6 +140,37 @@ func (jd *JobDB) SelectAllJobData() ([]JobData, error) { return jobs, nil } +func (jd *JobDB) PopbyAgentUUID(agentUUID string) (*JobData, error, bool) { + + db, err := getDBPtr() + if err != nil { + return nil, err, false + } + defer db.Close() + + selectSQL := `SELECT id, ProcedureID, AgentUUID, InstructionUUID, CreateAt FROM jobs` + + rows, err := db.Query(selectSQL) + defer rows.Close() + if err != nil { + return nil, err, false + } + + for rows.Next() == true { + var job *JobData = &JobData{} + err = rows.Scan(&job.Id, &job.ProcedureID, &job.AgentUUID, &job.InstructionUUID, &job.CreateAt) // 첫 행에만 적용 + if err != nil { + return nil, err, false + } + if agentUUID == job.AgentUUID { + jd.DeleteJobDataById(job.Id) + return job, nil, true + } + } + + return &JobData{}, nil, false +} + // DeleteJobDataByInstructionUUID: InstructionUUID 기반으로 JobData 삭제 func (jd *JobDB) DeleteJobDataByInstructionUUID(instructionUUID string) error { db, err := getDBPtr() @@ -146,6 +187,21 @@ func (jd *JobDB) DeleteJobDataByInstructionUUID(instructionUUID string) error { return nil } +func (jd *JobDB) DeleteJobDataById(id int) error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + deleteSQL := `DELETE FROM jobs WHERE id = ?` + _, err = db.Exec(deleteSQL, id) + if err != nil { + return fmt.Errorf("delete job failed: %w", err) + } + return nil +} + // DeleteJobDataByInstructionUUID: InstructionUUID 기반으로 JobData 삭제 func (jd *JobDB) DeleteAllJobData() error { db, err := getDBPtr() diff --git a/Model/OperationLog.go b/Model/OperationLog.go index 0f69f6e..a3cba3a 100644 --- a/Model/OperationLog.go +++ b/Model/OperationLog.go @@ -27,23 +27,21 @@ type OperationLogDocument struct { } type OperationLogDB struct { - Collection *mongo.Collection + DBNAME string } func NewOperationLogDB() (*OperationLogDB, error) { + return &OperationLogDB{DBNAME: "execLog"}, nil +} + +func (repo *OperationLogDB) InsertDocument(log OperationLogDocument) (*mongo.InsertOneResult, error) { db, err := getCollectionPtr() if err != nil { return nil, err } - OpDB := &OperationLogDB{ - Collection: db.Collection("execLog"), - } - return OpDB, nil -} - -func (repo *OperationLogDB) InsertDocument(log OperationLogDocument) (*mongo.InsertOneResult, error) { + ptrdb := db.Collection(repo.DBNAME) // Command 필드를 기본값으로 설정 (필요에 따라 변경) - result, err := repo.Collection.InsertOne(context.TODO(), log) + result, err := ptrdb.InsertOne(context.TODO(), log) fmt.Println(log) if err != nil { return nil, err @@ -54,10 +52,16 @@ func (repo *OperationLogDB) InsertDocument(log OperationLogDocument) (*mongo.Ins } func (repo *OperationLogDB) SelectDocumentById(id string) (*OperationLogDocument, error) { + db, err := getCollectionPtr() + if err != nil { + return nil, err + } + ptrdb := db.Collection(repo.DBNAME) + var OperationLogDocument OperationLogDocument filter := bson.M{"instructionUUID": id} - err := repo.Collection.FindOne(context.TODO(), filter).Decode(&OperationLogDocument) + err = ptrdb.FindOne(context.TODO(), filter).Decode(&OperationLogDocument) if err != nil { return nil, err } @@ -65,25 +69,51 @@ func (repo *OperationLogDB) SelectDocumentById(id string) (*OperationLogDocument return &OperationLogDocument, nil } -func (repo *OperationLogDB) SelectAllDocuments() (*OperationLogDocument, error) { - var OperationLogDocument OperationLogDocument +func (repo *OperationLogDB) SelectAllDocuments() ([]OperationLogDocument, error) { + documents := []OperationLogDocument{} + db, err := getCollectionPtr() + if err != nil { + return documents, err + } + ptrdb := db.Collection(repo.DBNAME) + filter := bson.M{} - err := repo.Collection.FindOne(context.TODO(), filter).Decode(&OperationLogDocument) + cursor, err := ptrdb.Find(context.TODO(), filter) if err != nil { - return nil, err + return documents, err } - return &OperationLogDocument, nil + defer cursor.Close(context.TODO()) + + for cursor.Next(context.TODO()) { + var doc OperationLogDocument + if err := cursor.Decode(&doc); err != nil { + return nil, err + } + documents = append(documents, doc) + } + + if err := cursor.Err(); err != nil { + return documents, err + } + + return documents, nil } func (repo *OperationLogDB) UpdateDocumentByInstID(id string, updateData bson.M) (*mongo.UpdateResult, error) { + db, err := getCollectionPtr() + if err != nil { + return nil, err + } + ptrdb := db.Collection(repo.DBNAME) + filter := bson.M{"instructionUUID": id} update := bson.M{ "$set": updateData, } - result, err := repo.Collection.UpdateOne(context.TODO(), filter, update) + result, err := ptrdb.UpdateOne(context.TODO(), filter, update) if err != nil { return nil, err } @@ -93,9 +123,15 @@ func (repo *OperationLogDB) UpdateDocumentByInstID(id string, updateData bson.M) } func (repo *OperationLogDB) DeleteAllDocument() (*mongo.DeleteResult, error) { + db, err := getCollectionPtr() + if err != nil { + return nil, err + } + ptrdb := db.Collection(repo.DBNAME) + filter := bson.M{} - result, err := repo.Collection.DeleteMany(context.TODO(), filter) + result, err := ptrdb.DeleteMany(context.TODO(), filter) if err != nil { return nil, err } diff --git a/Model/SystemInfoDB.go b/Model/SystemInfoDB.go index 0322173..4d0124d 100644 --- a/Model/SystemInfoDB.go +++ b/Model/SystemInfoDB.go @@ -137,7 +137,7 @@ func (s *SystemInfoDB) UpdateRecord(data *DsystemInfoDB) error { } defer db.Close() - rows, err := s.SelectRecords() + rows, err := s.SelectAllRecords() if err != nil { return err } @@ -188,7 +188,7 @@ func (s *SystemInfoDB) DeleteAllRecord() error { return nil } -func (s *SystemInfoDB) SelectRecords() ([]DsystemInfoDB, error) { +func (s *SystemInfoDB) SelectAllRecords() ([]DsystemInfoDB, error) { db, err := getDBPtr() if err != nil { return nil, err @@ -202,7 +202,7 @@ func (s *SystemInfoDB) SelectRecords() ([]DsystemInfoDB, error) { return nil, err } - var rows []DsystemInfoDB + rows := []DsystemInfoDB{} for row.Next() { var data DsystemInfoDB diff --git a/Model/nosqldb.go b/Model/nosqldb.go index 70b4022..5a19966 100644 --- a/Model/nosqldb.go +++ b/Model/nosqldb.go @@ -2,6 +2,7 @@ package Model import ( "context" + "fmt" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" "log" @@ -31,6 +32,11 @@ func getCollectionPtr() (*mongo.Database, error) { return nil, err } + err = client.Ping(context.TODO(), nil) + if err != nil { + return nil, fmt.Errorf("failed to connect to MongoDB: %v", err) + } + // 연결 설정 ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel() diff --git a/docs/docs.go b/docs/docs.go index 7372b39..a63bf19 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -9,11 +9,11 @@ const docTemplate = `{ "info": { "description": "{{escape .Description}}", "title": "{{.Title}}", - "termsOfService": "http://managingserver.io/terms/", + "termsOfService": "http://swagger.io/terms/", "contact": { - "name": "ManagingServer API Support", - "url": "http://managingserver.io/support", - "email": "support@managingserver.io" + "name": "API Support", + "url": "http://www.swagger.io/support", + "email": "support@swagger.io" }, "license": { "name": "Apache 2.0", @@ -56,7 +56,7 @@ const docTemplate = `{ "agentUUID": { "description": "example: Test", "type": "string", - "default": "c3cb84233416497694569d759a8a13e7" + "default": "937640a858ad48e9bc2787e8c4456ced" }, "instructionUUID": { "type": "string", @@ -75,11 +75,11 @@ const docTemplate = `{ // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ Version: "1.0", - Host: "localhost:80", + Host: "petstore.swagger.io", BasePath: "/", Schemes: []string{}, - Title: "ManagingServer API", - Description: "This is a sample server for the ManagingServer project.", + Title: "Swagger Example API", + Description: "This is a sample server Petstore server.", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, LeftDelim: "{{", diff --git a/docs/swagger.json b/docs/swagger.json index 78ad96a..e6e17bc 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1,13 +1,13 @@ { "swagger": "2.0", "info": { - "description": "This is a sample server for the ManagingServer project.", - "title": "ManagingServer API", - "termsOfService": "http://managingserver.io/terms/", + "description": "This is a sample server Petstore server.", + "title": "Swagger Example API", + "termsOfService": "http://swagger.io/terms/", "contact": { - "name": "ManagingServer API Support", - "url": "http://managingserver.io/support", - "email": "support@managingserver.io" + "name": "API Support", + "url": "http://www.swagger.io/support", + "email": "support@swagger.io" }, "license": { "name": "Apache 2.0", @@ -15,7 +15,7 @@ }, "version": "1.0" }, - "host": "localhost:80", + "host": "petstore.swagger.io", "basePath": "/", "paths": { "/api/postInst": { @@ -50,7 +50,7 @@ "agentUUID": { "description": "example: Test", "type": "string", - "default": "c3cb84233416497694569d759a8a13e7" + "default": "937640a858ad48e9bc2787e8c4456ced" }, "instructionUUID": { "type": "string", diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 0c8edca..8faadcf 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -3,7 +3,7 @@ definitions: router.InstructionD: properties: agentUUID: - default: c3cb84233416497694569d759a8a13e7 + default: 937640a858ad48e9bc2787e8c4456ced description: 'example: Test' type: string instructionUUID: @@ -14,18 +14,18 @@ definitions: description: 'example: Test' type: string type: object -host: localhost:80 +host: petstore.swagger.io info: contact: - email: support@managingserver.io - name: ManagingServer API Support - url: http://managingserver.io/support - description: This is a sample server for the ManagingServer project. + email: support@swagger.io + name: API Support + url: http://www.swagger.io/support + description: This is a sample server Petstore server. license: name: Apache 2.0 url: http://www.apache.org/licenses/LICENSE-2.0.html - termsOfService: http://managingserver.io/terms/ - title: ManagingServer API + termsOfService: http://swagger.io/terms/ + title: Swagger Example API version: "1.0" paths: /api/postInst: diff --git a/go.mod b/go.mod deleted file mode 100644 index 94f549f..0000000 --- a/go.mod +++ /dev/null @@ -1,81 +0,0 @@ -module github.com/your/repo - -go 1.23.0 - -require ( - github.com/HTTPs-omma/HSProtocol v1.0.3 - github.com/gin-gonic/gin v1.10.0 - github.com/gofiber/fiber/v3 v3.0.0-beta.3 - github.com/joho/godotenv v1.5.1 - github.com/stretchr/testify v1.9.0 - github.com/swaggo/files v1.0.1 - github.com/swaggo/gin-swagger v1.6.0 - github.com/swaggo/swag v1.16.3 - go.mongodb.org/mongo-driver v1.16.1 - gopkg.in/yaml.v2 v2.4.0 - modernc.org/sqlite v1.33.0 -) - -require ( - github.com/KyleBanks/depth v1.2.1 // indirect - github.com/andybalholm/brotli v1.1.0 // indirect - github.com/bytedance/sonic v1.12.2 // indirect - github.com/bytedance/sonic/loader v0.2.0 // indirect - github.com/cloudwego/base64x v0.1.4 // indirect - github.com/cloudwego/iasm v0.2.0 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/gabriel-vasile/mimetype v1.4.5 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.21.0 // indirect - github.com/go-openapi/spec v0.21.0 // indirect - github.com/go-openapi/swag v0.23.0 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.22.1 // indirect - github.com/goccy/go-json v0.10.3 // indirect - github.com/gofiber/utils/v2 v2.0.0-beta.6 // indirect - github.com/golang/snappy v0.0.4 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.9 // indirect - github.com/klauspost/cpuid/v2 v2.2.8 // indirect - github.com/leodido/go-urn v1.4.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/montanaflynn/stats v0.7.1 // indirect - github.com/ncruces/go-strftime v0.1.9 // indirect - github.com/pelletier/go-toml/v2 v2.2.3 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/rogpeppe/go-internal v1.12.0 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.12 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.55.0 // indirect - github.com/valyala/tcplisten v1.0.0 // indirect - github.com/xdg-go/pbkdf2 v1.0.0 // indirect - github.com/xdg-go/scram v1.1.2 // indirect - github.com/xdg-go/stringprep v1.0.4 // indirect - github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect - golang.org/x/arch v0.10.0 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect - golang.org/x/tools v0.25.0 // indirect - google.golang.org/protobuf v1.34.2 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect - modernc.org/mathutil v1.6.0 // indirect - modernc.org/memory v1.8.0 // indirect - modernc.org/strutil v1.2.0 // indirect - modernc.org/token v1.1.0 // indirect -) diff --git a/go.sum b/go.sum deleted file mode 100644 index 721d918..0000000 --- a/go.sum +++ /dev/null @@ -1,212 +0,0 @@ -github.com/HTTPs-omma/HSProtocol v1.0.3 h1:8OZxA4Vc2H1QsTLPYQ8B7++B5r0M8g6Gaom/IZ2JHvg= -github.com/HTTPs-omma/HSProtocol v1.0.3/go.mod h1:IvJQe3yhvo0qunuPoB499HuGBGE3QS0MWU8OYRuvAus= -github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= -github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= -github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= -github.com/bytedance/sonic v1.12.2 h1:oaMFuRTpMHYLpCntGca65YWt5ny+wAceDERTkT2L9lg= -github.com/bytedance/sonic v1.12.2/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= -github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= -github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= -github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= -github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= -github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= -github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= -github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= -github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= -github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= -github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= -github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= -github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= -github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA= -github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= -github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= -github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= -github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTYz/L20vrg= -github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY= -github.com/gofiber/utils/v2 v2.0.0-beta.6 h1:ED62bOmpRXdgviPlfTmf0Q+AXzhaTUAFtdWjgx+XkYI= -github.com/gofiber/utils/v2 v2.0.0-beta.6/go.mod h1:3Kz8Px3jInKFvqxDzDeoSygwEOO+3uyubTmUa6PqY+0= -github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= -github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= -github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= -github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= -github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= -github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= -github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= -github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= -github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= -github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= -github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= -github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= -github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= -github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= -github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= -github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.55.0 h1:Zkefzgt6a7+bVKHnu/YaYSOPfNYNisSVBo/unVCf8k8= -github.com/valyala/fasthttp v1.55.0/go.mod h1:NkY9JtkrpPKmgwV3HTaS2HWaJss9RSIsRVfcxxoHiOM= -github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= -github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= -github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= -github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= -github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= -github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mongodb.org/mongo-driver v1.16.1 h1:rIVLL3q0IHM39dvE+z2ulZLp9ENZKThVfuvN/IiN4l8= -go.mongodb.org/mongo-driver v1.16.1/go.mod h1:oB6AhJQvFQL4LEHyXi6aJzQJtBiTQHiAd83l0GdFaiw= -golang.org/x/arch v0.10.0 h1:S3huipmSclq3PJMNe76NGwkBR504WFkQ5dhzWzP8ZW8= -golang.org/x/arch v0.10.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= -golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= -modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI= -modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= -modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= -modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= -modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= -modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= -modernc.org/sqlite v1.33.0 h1:WWkA/T2G17okiLGgKAj4/RMIvgyMT19yQ038160IeYk= -modernc.org/sqlite v1.33.0/go.mod h1:9uQ9hF/pCZoYZK73D/ud5Z7cIRIILSZI8NdIemVMTX8= -modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= -modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= -modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/main.go b/main.go index 6b9d2ab..464130c 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,7 @@ package main import ( "bytes" "fmt" - "github.com/HTTPs-omma/HSProtocol/HSProtocol" + "github.com/HTTPs-omma/HTTPsBAS-HSProtocol/HSProtocol" "github.com/gin-gonic/gin" "github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3/middleware/cors" diff --git a/router/api.go b/router/api.go index 790a86f..3241636 100644 --- a/router/api.go +++ b/router/api.go @@ -2,7 +2,7 @@ package router import ( "fmt" - "github.com/HTTPs-omma/HSProtocol/HSProtocol" + "github.com/HTTPs-omma/HTTPsBAS-HSProtocol/HSProtocol" "github.com/gofiber/fiber/v3" "github.com/your/repo/Core" "github.com/your/repo/Model" @@ -15,7 +15,7 @@ type InstructionD struct { // example: Test ProcedureID string `json:"procedureID" default:"P_Collection_Kimsuky_001"` // example: Test - AgentUUID string `json:"agentUUID" default:"c3cb84233416497694569d759a8a13e7"` + AgentUUID string `json:"agentUUID" default:"937640a858ad48e9bc2787e8c4456ced"` InstructionUUID string `json:"instructionUUID" default:"32a2833486414af9bc4596caef585538"` } @@ -60,7 +60,6 @@ func checkInstReq(ctx fiber.Ctx) error { // @Accept json // @Produce json // @Param loginUserRequest body InstructionD true "request job" -// @Default {"procedureID": "P_Collection_Kimsuky_001", "agentUUID": "2023-09-15T10:00:00Z", "instructionUUID" : :"550e8400-e29b-41d4-a716-446655440000"} // @Router /api/postInst [post] func postInst(ctx fiber.Ctx) error { // https://github.com/gofiber/fiber/issues/2958 @@ -71,13 +70,14 @@ func postInst(ctx fiber.Ctx) error { ctx.Status(404) return ctx.Send([]byte(err.Error())) } - jobMgr, err := Core.NewJobManager() + jobdb, err := Model.NewJobDB() if err != nil { return ctx.Send([]byte(err.Error())) } - fmt.Println("test : ", InstD.ProcedureID, InstD.AgentUUID, InstD.InstructionUUID) + //fmt.Println("test : ", InstD.ProcedureID, InstD.AgentUUID, InstD.InstructionUUID) - err = jobMgr.InsertData(&Model.JobData{ + err = jobdb.InsertJobData(&Model.JobData{ + 0, InstD.ProcedureID, InstD.AgentUUID, InstD.InstructionUUID, diff --git a/router/view.go b/router/view.go index de9f8f9..7bb77b1 100644 --- a/router/view.go +++ b/router/view.go @@ -8,37 +8,36 @@ import ( // 통합 구조체 정의 type CombinedData struct { - OperationLog Model.OperationLogDocument `json:"operation_log"` - AgentStatus []Model.AgentStatusRecord `json:"agent_status"` - Application []Model.DapplicationDB `json:"application"` - JobData []Model.JobData `json:"job_data"` - SystemInfo []Model.DsystemInfoDB `json:"system_info"` + OperationLog []Model.OperationLogDocument `json:"operation_log"` + AgentStatus []Model.AgentStatusRecord `json:"agent_status"` + Application []Model.DapplicationDB `json:"application"` + JobData []Model.JobData `json:"job_data"` + SystemInfo []Model.DsystemInfoDB `json:"system_info"` } func SetupViewRoutes(app *fiber.App) { app.Get("/combined-data", func(ctx fiber.Ctx) error { dbOperationLog, err := Model.NewOperationLogDB() if err != nil { - ctx.Status(404) - return ctx.SendString("Error : " + err.Error()) + return ctx.Status(404).SendString("Error : " + err.Error()) } // 모든 문서 조회 - dataOL, err := dbOperationLog.SelectAllDocuments() + var dataOL []Model.OperationLogDocument + dataOL, err = dbOperationLog.SelectAllDocuments() if err != nil { - ctx.Status(404) - return ctx.SendString("Error : " + err.Error()) + //dataOL = make([]Model.OperationLogDocument, 0) + //fmt.Println("SelectAllDocuments Error : " + err.Error()) + //return ctx.Status(404).SendString("Error : " + err.Error()) } dbAgentStatus, err := Model.NewAgentStatusDB() if err != nil { - ctx.Status(404) - return ctx.SendString("Error : " + err.Error()) + return ctx.Status(404).SendString("Error : " + err.Error()) } - dataAS, err := dbAgentStatus.SelectRecords() + dataAS, err := dbAgentStatus.SelectAllRecords() if err != nil { fmt.Println("Error selecting records:", err) - ctx.Status(404) - return ctx.SendString("Error : " + err.Error()) + return ctx.Status(404).SendString("Error : " + err.Error()) } appdb, err := Model.NewApplicationDB() @@ -67,7 +66,7 @@ func SetupViewRoutes(app *fiber.App) { if err != nil { return err } - dataSys, err := dbSysInfo.SelectRecords() + dataSys, err := dbSysInfo.SelectAllRecords() if err != nil { fmt.Println("Error selecting records:", err) ctx.Status(404) @@ -75,7 +74,7 @@ func SetupViewRoutes(app *fiber.App) { } combined := CombinedData{ - OperationLog: *dataOL, + OperationLog: dataOL, AgentStatus: dataAS, Application: dataAPP, JobData: dataJD, @@ -108,7 +107,7 @@ func SetupViewRoutes(app *fiber.App) { app.Get("/view/agentStatus", func(ctx fiber.Ctx) error { //data := ctx.Body() db, err := Model.NewAgentStatusDB() - datas, err := db.SelectRecords() + datas, err := db.SelectAllRecords() if err != nil { fmt.Println("Error selecting records:", err) ctx.Status(404) @@ -151,7 +150,7 @@ func SetupViewRoutes(app *fiber.App) { if err != nil { return err } - datas, err := db.SelectRecords() + datas, err := db.SelectAllRecords() if err != nil { fmt.Println("Error selecting records:", err) ctx.Status(404) diff --git a/view/html/viewdata.html b/view/html/viewdata.html index 945094e..d281f5f 100644 --- a/view/html/viewdata.html +++ b/view/html/viewdata.html @@ -146,6 +146,7 @@

Combined Data Tables

+ @@ -242,10 +243,11 @@

Combined Data Tables

data.job_data.forEach(job => { jobDataTable.innerHTML += ` - - - - + + + + + `; }); @@ -284,8 +286,9 @@

Combined Data Tables

}); } + fetchData() // 1초마다 데이터 업데이트 - setInterval(fetchData, 1000); + setInterval(fetchData, 2000); From 476bffdaa205447f911302f2924d3cfcf9885cab Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Wed, 18 Sep 2024 04:14:43 +0900 Subject: [PATCH 19/26] =?UTF-8?q?HTTPS-53=20<=20=EC=BB=A4=EB=B0=8B?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=ED=95=9C=EA=B1=B0=20=EB=B3=B5=EA=B5=AC....?= =?UTF-8?q?=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Model/test.py | 26 +++++++ db.db | Bin 0 -> 36864 bytes go.mod | 81 +++++++++++++++++++ go.sum | 212 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 319 insertions(+) create mode 100644 Model/test.py create mode 100644 db.db create mode 100644 go.mod create mode 100644 go.sum diff --git a/Model/test.py b/Model/test.py new file mode 100644 index 0000000..c224ddf --- /dev/null +++ b/Model/test.py @@ -0,0 +1,26 @@ +import requests +import json + +# 요청할 URL +url = 'http://127.0.0.1/postInstruction' + +# 전송할 데이터 +data = { + "agentUUID": "12342", + "procedureID": "P_Collection_Kimsuky_001", + "instructionUUID": "f5556669-ffbe-4d24-b833-fc9888fdeaef" +} + +# 헤더 설정 +headers = { + 'Content-Type': 'application/json' +} + +# POST 요청 전송 +response = requests.post(url, headers=headers, data=json.dumps(data)) + +# 응답 출력 +if response.status_code == 200: + print("Request succeeded:", response.json()) +else: + print(f"Request failed with status code {response.status_code}: {response.text}") diff --git a/db.db b/db.db new file mode 100644 index 0000000000000000000000000000000000000000..5e961f5b9bf7930f398e65be45834655261daf3a GIT binary patch literal 36864 zcmeI2&2JM|5WwvwI58qgi$FQ_>qWUFB3S!rdxKCh@g{L`oZ#3{PS$3e+F{AiU#UhtugeMu@}VI07Fxe2T{&IH@l-;M-YozTN2&hv%D# zrsn?~?)sOGmUv5D({l5l`~GtMz3*!MOV{n~#IPR;AOR#$D}nQ$Ha4`jwK*>)3}qy( z4Nv9_Z9J42)yrp%JyAIjlSwRaJS>xPKk3-(cDqwa5{ks+J~>K;qM?C6^b9#6pCN&G zY%ml7$pJYM>mqO*K1|G+XXbBHBoyo-)}49t`yYw*U}<%Eit5SdK~qfrEJh-O@QH`R zB%ev0%WJkURj_`5o_IVI{8FG&fiW#(&?Y$*i1zdcq8*$lc6QOBem!SIlyQyZjBF}1 zX7>%|Hus#;vbmI=sl2RL8Be7rD|-T2^>e8Ds*%rDDLkQNGg^8J6~}emh^1imAfStd z24s7FHLEFx7BEV^Bq;X=;^7$SiASSADnTzDjs*sW?CbLr$(>#gE_d>7S8HFJ(~-&~ zwXbvM(qM5y$s4-ePLv~;V9V$3E5}?7t?lj3>wR_x1STfZDOE85NyVwFDhDbCYD@x% z;cN2X6%n;#R~6@CPHg^$S**K@Yd>5f*3vWc!7R;)Vwj35M5c3Na+MU7<;^Fv)?HgZ ztYpUW%9vKlHFkRiC3$P^RVZ9J!`<~kl1IVwEL`wqs?PST`QS z;$r^v0#aknTDY*b@Q7MeOUbos)7?wfAJ@#Q;OY4#Yj%ZLR~A>7?fbumY7BV-R+?p9 zH!hgpEkhL6EP93 zlFAr%b0Vu7x(YcC9VDoYD*3cQ7<;IethMK@ZKEL8zcOLUh#+Cg4f;6SNH>^6@3>kI z9de$rfv)c}avJQ_GOD(rSyu&i!(c}S_Geun**V?eY-l}r&^g1~I=|3Ia`f{~l{D?4 z@vy7JPPUyuW+KhFz(ufPh* zD2xlD7?@8=j!ILt_gS&^_(H^X)FUJvW@GJc*VhZu=r$cfJ&EkC`&vHDN zwg02qV^~W#N?BE)#deEck5^;_iS<{T{uLJ(@Kmter2_OL^fCP{L5|z3Ysc-oFzl$S`t|0*=fCP{L5 Date: Wed, 18 Sep 2024 05:03:05 +0900 Subject: [PATCH 20/26] =?UTF-8?q?HTTPS-53=20<=20=EB=B3=B5=EA=B5=AC=20?= =?UTF-8?q?=E3=85=A0=E3=85=A0=E3=85=A0=E3=85=A0=E3=85=A0=E3=85=A0=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/CommandDispatcher.go | 139 ++++++++++++++++++-------------------- Model/JobData.go | 38 +++++++---- Model/nosqldb.go | 2 +- db.db | Bin 36864 -> 36864 bytes docs/docs.go | 2 +- docs/swagger.json | 2 +- docs/swagger.yaml | 2 +- go.mod | 1 + go.sum | 21 ++++++ main.go | 22 ++++-- router/api.go | 11 ++- 11 files changed, 140 insertions(+), 100 deletions(-) diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index 86d9427..1cb5b48 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -11,42 +11,32 @@ type CommandDispatcher struct { } // Command 상수를 정의 -const ( - ACK = 0b0000000000 - UPDATE_HEALTH = 0b0000000001 - UPDATE_PROTOCOL = 0b0000000010 - POST_SYSTEM_INFO = 0b0000000011 - RESERVED = 0b0000000100 - POST_APPLICATION_INFO = 0b0000000101 - GET_PROCEDURE = 0b0000000110 - POST_LOG_OF_PROCEDURE = 0b0000000111 -) func (cd *CommandDispatcher) Action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // hsMgr := HSProtocol.NewHSProtocolManager() switch hs.Command { - case UPDATE_HEALTH: - return updateHealth(hs) - case UPDATE_PROTOCOL: - return updateProtocol(hs) - case POST_SYSTEM_INFO: - return postSystemInfo(hs) - case RESERVED: + case HSProtocol.UPDATE_AGENT_PROTOCOL: + return UPDATE_AGENT_PROTOCOL(hs) + case HSProtocol.UPDATE_AGENT_STATUS: + return UPDATE_AGENT_STATUS(hs) + case HSProtocol.SEND_AGENT_SYS_INFO: + return SEND_AGENT_SYS_INFO(hs) + case HSProtocol.ERROR_ACK: break // 예약 - case POST_APPLICATION_INFO: - return postApplicationInfo(hs) - case GET_PROCEDURE: - return getProcedure(hs) - case POST_LOG_OF_PROCEDURE: - return postLogOfProcedure(hs) + case HSProtocol.SEND_AGENT_APP_INFO: + return SEND_AGENT_APP_INFO(hs) + case HSProtocol.FETCH_INSTRUCTION: + return FETCH_INSTRUCTION(hs) + case HSProtocol.SEND_PROCEDURE_LOG: + return SEND_PROCEDURE_LOG(hs) } return nil, fmt.Errorf("Invalid Command") } // Command: 1 (0b0000000001) -func updateHealth(hs *HSProtocol.HS) (*HSProtocol.HS, error) { +func UPDATE_AGENT_PROTOCOL(hs *HSProtocol.HS) (*HSProtocol.HS, error) { agsmd, err := Model.NewAgentStatusDB() if err != nil { return nil, err @@ -64,7 +54,7 @@ func updateHealth(hs *HSProtocol.HS) (*HSProtocol.HS, error) { return nil, err } - hs_uuid := string(hs.UUID[:]) + hs_uuid := HSProtocol.ByteArrayToHexString(hs.UUID) flag := false for _, record := range records { @@ -75,12 +65,12 @@ func updateHealth(hs *HSProtocol.HS) (*HSProtocol.HS, error) { if flag == true { agsmd.UpdateRecord(&Model.AgentStatusRecord{ - UUID: string(hs.UUID[:]), + UUID: hs_uuid, Status: Model.BinaryToAgentStatus(hs.HealthStatus), }) - return &HSProtocol.HS{ // ACK + return &HSProtocol.HS{ // HSProtocol.ACK ProtocolID: hs.ProtocolID, - Command: ACK, + Command: HSProtocol.ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -89,13 +79,13 @@ func updateHealth(hs *HSProtocol.HS) (*HSProtocol.HS, error) { }, nil } else if (flag == false) && (hs.HealthStatus == uint8(Model.WAIT)) { agsmd.InsertRecord(&Model.AgentStatusRecord{ - UUID: string(hs.UUID[:]), + UUID: hs_uuid, Status: Model.BinaryToAgentStatus(hs.HealthStatus), }) - return &HSProtocol.HS{ // ACK + return &HSProtocol.HS{ // HSProtocol.ACK ProtocolID: hs.ProtocolID, - Command: ACK, + Command: HSProtocol.ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -108,7 +98,7 @@ func updateHealth(hs *HSProtocol.HS) (*HSProtocol.HS, error) { } // Command: 2 (0b0000000010) -func updateProtocol(hs *HSProtocol.HS) (*HSProtocol.HS, error) { +func UPDATE_AGENT_STATUS(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // protocolID := binary.BigEndian.Uint32(hs.Data) agsmd, err := Model.NewAgentStatusDB() @@ -139,9 +129,9 @@ func updateProtocol(hs *HSProtocol.HS) (*HSProtocol.HS, error) { } } - return &HSProtocol.HS{ // ACK + return &HSProtocol.HS{ // HSProtocol.ACK ProtocolID: hs.ProtocolID, - Command: ACK, + Command: HSProtocol.ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -151,7 +141,7 @@ func updateProtocol(hs *HSProtocol.HS) (*HSProtocol.HS, error) { } // Command: 3 (0b0000000011) -func postSystemInfo(hs *HSProtocol.HS) (*HSProtocol.HS, error) { +func SEND_AGENT_SYS_INFO(hs *HSProtocol.HS) (*HSProtocol.HS, error) { sysDB, err := Model.NewSystemInfoDB() if err != nil { @@ -167,9 +157,9 @@ func postSystemInfo(hs *HSProtocol.HS) (*HSProtocol.HS, error) { return nil, err } - return &HSProtocol.HS{ // ACK + return &HSProtocol.HS{ // HSProtocol.ACK ProtocolID: hs.ProtocolID, - Command: ACK, + Command: HSProtocol.ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -179,7 +169,7 @@ func postSystemInfo(hs *HSProtocol.HS) (*HSProtocol.HS, error) { } // Command: 5 (0b0000000101) -func postApplicationInfo(hs *HSProtocol.HS) (*HSProtocol.HS, error) { +func SEND_AGENT_APP_INFO(hs *HSProtocol.HS) (*HSProtocol.HS, error) { appDB := Model.ApplicationDB{} Dapp, err := appDB.Unmarshal(hs.Data) @@ -191,9 +181,9 @@ func postApplicationInfo(hs *HSProtocol.HS) (*HSProtocol.HS, error) { return nil, err } - return &HSProtocol.HS{ // ACK + return &HSProtocol.HS{ // HSProtocol.ACK ProtocolID: hs.ProtocolID, - Command: ACK, + Command: HSProtocol.ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -203,44 +193,20 @@ func postApplicationInfo(hs *HSProtocol.HS) (*HSProtocol.HS, error) { } // Command: 6 (0b0000000110) -func getProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { - - appDB := Model.ApplicationDB{} - Dapp, err := appDB.Unmarshal(hs.Data) - if err != nil { - return nil, err - } - err = appDB.InsertRecord(Dapp) - if err != nil { - return nil, err - } - - return &HSProtocol.HS{ // ACK - ProtocolID: hs.ProtocolID, - Command: ACK, - UUID: hs.UUID, - HealthStatus: hs.HealthStatus, - Identification: hs.Identification, - TotalLength: hs.TotalLength, - Data: []byte{}, - }, nil -} - -// Command: 7 (0b0000000111) -func postLogOfProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { - - jobdb, err := Model.NewJobDB() // stack 에 있어야겠지? +func FETCH_INSTRUCTION(hs *HSProtocol.HS) (*HSProtocol.HS, error) { + agentUuid := HSProtocol.ByteArrayToHexString(hs.UUID) + fmt.Println("agent uuid : " + agentUuid) + jobdb, err := Model.NewJobDB() if err != nil { return nil, err } - var agentUuid string - copy(hs.UUID[:], agentUuid) job, err, exist := jobdb.PopbyAgentUUID(agentUuid) if err != nil { return nil, err } + //fmt.Println("debug === : " + job.ProcedureID) if exist == true { // job 이 있다면 cmdMgr, err := NewInstructionManager() if err != nil { @@ -255,9 +221,9 @@ func postLogOfProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { if err != nil { return nil, err } - return &HSProtocol.HS{ // ACK + return &HSProtocol.HS{ // HSProtocol.ACK ProtocolID: hs.ProtocolID, - Command: ACK, + Command: HSProtocol.ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, @@ -267,9 +233,36 @@ func postLogOfProcedure(hs *HSProtocol.HS) (*HSProtocol.HS, error) { } // false - return &HSProtocol.HS{ // ACK + return &HSProtocol.HS{ // HSProtocol.ACK + ProtocolID: hs.ProtocolID, + Command: HSProtocol.ACK, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + }, nil + +} + +// Command: 7 (0b0000000111) +func SEND_PROCEDURE_LOG(hs *HSProtocol.HS) (*HSProtocol.HS, error) { + + //hs_uuid := HSProtocol.ByteArrayToHexString(hs.UUID) + + appDB := Model.ApplicationDB{} + Dapp, err := appDB.Unmarshal(hs.Data) + if err != nil { + return nil, err + } + err = appDB.InsertRecord(Dapp) + if err != nil { + return nil, err + } + + return &HSProtocol.HS{ // HSProtocol.ACK ProtocolID: hs.ProtocolID, - Command: ACK, + Command: HSProtocol.ACK, UUID: hs.UUID, HealthStatus: hs.HealthStatus, Identification: hs.Identification, diff --git a/Model/JobData.go b/Model/JobData.go index 7ca0d1f..ddc9973 100644 --- a/Model/JobData.go +++ b/Model/JobData.go @@ -1,6 +1,7 @@ package Model import ( + "database/sql" "fmt" "time" ) @@ -141,34 +142,41 @@ func (jd *JobDB) SelectAllJobData() ([]JobData, error) { } func (jd *JobDB) PopbyAgentUUID(agentUUID string) (*JobData, error, bool) { - db, err := getDBPtr() if err != nil { return nil, err, false } defer db.Close() - selectSQL := `SELECT id, ProcedureID, AgentUUID, InstructionUUID, CreateAt FROM jobs` + // 쿼리문 수정: WHERE 절을 추가하고 ORDER BY를 사용하여 CreateAt을 기준으로 내림차순 정렬 + selectSQL := ` + SELECT id, ProcedureID, AgentUUID, InstructionUUID, CreateAt + FROM jobs + WHERE AgentUUID = ? + ORDER BY CreateAt DESC + LIMIT 1 + ` - rows, err := db.Query(selectSQL) - defer rows.Close() + // QueryRow를 사용하여 한 행만 가져옵니다. + row := db.QueryRow(selectSQL, agentUUID) + + var job JobData + err = row.Scan(&job.Id, &job.ProcedureID, &job.AgentUUID, &job.InstructionUUID, &job.CreateAt) if err != nil { + if err == sql.ErrNoRows { + // 일치하는 행이 없는 경우 + return &JobData{}, nil, false + } return nil, err, false } - for rows.Next() == true { - var job *JobData = &JobData{} - err = rows.Scan(&job.Id, &job.ProcedureID, &job.AgentUUID, &job.InstructionUUID, &job.CreateAt) // 첫 행에만 적용 - if err != nil { - return nil, err, false - } - if agentUUID == job.AgentUUID { - jd.DeleteJobDataById(job.Id) - return job, nil, true - } + // 해당 JobData를 삭제 + err = jd.DeleteJobDataById(job.Id) + if err != nil { + return nil, err, false } - return &JobData{}, nil, false + return &job, nil, true } // DeleteJobDataByInstructionUUID: InstructionUUID 기반으로 JobData 삭제 diff --git a/Model/nosqldb.go b/Model/nosqldb.go index 5a19966..9d18502 100644 --- a/Model/nosqldb.go +++ b/Model/nosqldb.go @@ -24,7 +24,7 @@ func getCollectionPtr() (*mongo.Database, error) { SetMaxPoolSize(50). // 최대 풀 크기 SetMinPoolSize(10). // 최소 풀 크기 SetMaxConnIdleTime(30 * time.Second) // 최대 유휴 시간 - + //fmt.Println("mongodb://" + MONGOID + ":" + MONGOPW + "@uskawjdu.iptime.org:17017/") // 클라이언트 생성 client, err := mongo.NewClient(clientOptions) if err != nil { diff --git a/db.db b/db.db index 5e961f5b9bf7930f398e65be45834655261daf3a..83cca8bdbbbaaa0a13985e561ea3885d5a22a270 100644 GIT binary patch delta 779 zcmZwFJxYT?5C-5Rh33a3VoLuas8OTq?#%4YY#<_7N#nP~0mU7)*@9}NCc?Z<7u46?33!p%=t-aRG%jHXr4QcHJBkvIsyO9=j^WBaT44q^@5TyaLxOtO@2?ikE zkdK%__Etj2!^S~^X@T%Lit<$LgI(n(rcFL<<^|ta>IVrEoXQkPC&)k)Y zX??el8w`gJi|AmCY)}($2?dK1ASN_DPylm&acS-cJ+dB=S<`y!yK1y2G`WtwBk~x$ zN>ISvC4mL1&#ds4J3yxUCebViJ(nr~+YvR~4 X3aHQ~?Ja}G%JKTW6V;;bGmJg}8v<_T diff --git a/docs/docs.go b/docs/docs.go index a63bf19..a39a64f 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -75,7 +75,7 @@ const docTemplate = `{ // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ Version: "1.0", - Host: "petstore.swagger.io", + Host: "localhost", BasePath: "/", Schemes: []string{}, Title: "Swagger Example API", diff --git a/docs/swagger.json b/docs/swagger.json index e6e17bc..4f0ecde 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -15,7 +15,7 @@ }, "version": "1.0" }, - "host": "petstore.swagger.io", + "host": "localhost", "basePath": "/", "paths": { "/api/postInst": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 8faadcf..fda1f77 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -14,7 +14,7 @@ definitions: description: 'example: Test' type: string type: object -host: petstore.swagger.io +host: localhost info: contact: email: support@swagger.io diff --git a/go.mod b/go.mod index 9197de6..ccba599 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/gabriel-vasile/mimetype v1.4.5 // indirect + github.com/gin-contrib/cors v1.3.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect diff --git a/go.sum b/go.sum index d207661..8d2d081 100644 --- a/go.sum +++ b/go.sum @@ -21,10 +21,16 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= +github.com/gin-contrib/cors v1.3.0 h1:PolezCc89peu+NgkIWt9OB01Kbzt6IP0J/JvkG6xxlg= +github.com/gin-contrib/cors v1.3.0/go.mod h1:artPvLlhkF7oG06nK8v3U8TNz6IeX+w1uzCSEId5/Vc= +github.com/gin-contrib/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw= +github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E= github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= +github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= @@ -49,6 +55,7 @@ github.com/gofiber/fiber/v3 v3.0.0-beta.3 h1:7Q2I+HsIqnIEEDB+9oe7Gadpakh6ZLhXpTY github.com/gofiber/fiber/v3 v3.0.0-beta.3/go.mod h1:kcMur0Dxqk91R7p4vxEpJfDWZ9u5IfvrtQc8Bvv/JmY= github.com/gofiber/utils/v2 v2.0.0-beta.6 h1:ED62bOmpRXdgviPlfTmf0Q+AXzhaTUAFtdWjgx+XkYI= github.com/gofiber/utils/v2 v2.0.0-beta.6/go.mod h1:3Kz8Px3jInKFvqxDzDeoSygwEOO+3uyubTmUa6PqY+0= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -64,6 +71,7 @@ github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= @@ -72,8 +80,11 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= @@ -82,12 +93,14 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= @@ -121,6 +134,7 @@ github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -149,6 +163,7 @@ golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt7 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -160,6 +175,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -188,8 +205,12 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index 464130c..5e335fb 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "github.com/HTTPs-omma/HTTPsBAS-HSProtocol/HSProtocol" + cors2 "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" "github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3/middleware/cors" @@ -25,7 +26,7 @@ import ( // @contact.email support@swagger.io // @license.name Apache 2.0 // @license.url http://www.apache.org/licenses/LICENSE-2.0.html -// @host petstore.swagger.io +// @host localhost // @BasePath / // @Path api var testCommand string = "dir /" @@ -57,8 +58,14 @@ func Swagger() { // Swagger 엔드포인트 r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) - - r.Run(":8080") + r.Use(cors2.New(cors2.Config{ + AllowOrigins: []string{"*"}, // 모든 도메인 허용, 보안 상 필요한 경우 특정 도메인만 허용해야 함 + AllowMethods: []string{"GET", "POST", "PUT", "DELETE"}, // 허용할 HTTP 메서드 + AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization", "Access-Control-Allow-Origin", "Connection", "Accept-Encoding"}, + ExposeHeaders: []string{"Content-Length"}, + AllowCredentials: true, + })) + r.Run("localhost:8000") } @@ -130,9 +137,14 @@ func HTTPServer() { }) // 효과적인 Cors 에러 해결 + //app.Use(cors.New(cors.Config{ + // AllowCredentials: true, + // AllowOriginsFunc: func(origin string) bool { return true }, + //})) app.Use(cors.New(cors.Config{ - AllowCredentials: true, - AllowOriginsFunc: func(origin string) bool { return true }, + AllowOrigins: []string{"*", "http://localhost/*"}, + AllowHeaders: []string{"Origin", "Content-Type", "Accept"}, + //AllowCredentials: true, })) router.SetupAPIRoutes(app) diff --git a/router/api.go b/router/api.go index 3241636..d7c42d8 100644 --- a/router/api.go +++ b/router/api.go @@ -42,15 +42,20 @@ func checkInstReq(ctx fiber.Ctx) error { HSMgr := HSProtocol.NewHSProtocolManager() hs, err := HSMgr.Parsing(req) if err != nil { + fmt.Println(err) ctx.Status(404) return fmt.Errorf("Error parsing:", err) } - fmt.Println("hs.uuid : ", hs.UUID) + //fmt.Println("hs.uuid : ", hs.UUID) dipt := Core.CommandDispatcher{} - dipt.Action(hs) + ack, err := dipt.Action(hs) + if err != nil { + fmt.Println(err) + } - return nil + rstb, err := HSMgr.ToBytes(ack) + return ctx.Send(rstb) } // postInst example From 7344299477fd5b1fa8a2d0ab1b32fb23ca73a747 Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Wed, 18 Sep 2024 07:23:39 +0900 Subject: [PATCH 21/26] =?UTF-8?q?HTTPS-53=20<=20=EB=AD=94=EA=B0=80=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=ED=96=88=EB=8A=94=EB=8D=B0=20=EA=B9=8C?= =?UTF-8?q?=EB=A8=B9=EC=9D=8C.=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/CommandDispatcher.go | 98 +++++++++++++++--------------- Model/AgentStatus.go | 16 ++++- Model/ApplicationDB.go | 124 ++++++++++++++++++++++++-------------- Model/OperationLog.go | 6 ++ Model/SystemInfoDB.go | 1 - db.db | Bin 36864 -> 147456 bytes main.go | 1 - router/api.go | 11 ++++ view/html/viewdata.html | 60 ++++++++++++------ 9 files changed, 195 insertions(+), 122 deletions(-) diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index 1cb5b48..0be5ee9 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -1,6 +1,7 @@ package Core import ( + "encoding/json" "fmt" "github.com/HTTPs-omma/HTTPsBAS-HSProtocol/HSProtocol" "github.com/your/repo/Model" @@ -28,8 +29,8 @@ func (cd *CommandDispatcher) Action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { return SEND_AGENT_APP_INFO(hs) case HSProtocol.FETCH_INSTRUCTION: return FETCH_INSTRUCTION(hs) - case HSProtocol.SEND_PROCEDURE_LOG: - return SEND_PROCEDURE_LOG(hs) + //case HSProtocol.SEND_PROCEDURE_LOG: + // return SEND_PROCEDURE_LOG(hs) } return nil, fmt.Errorf("Invalid Command") @@ -101,33 +102,21 @@ func UPDATE_AGENT_PROTOCOL(hs *HSProtocol.HS) (*HSProtocol.HS, error) { func UPDATE_AGENT_STATUS(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // protocolID := binary.BigEndian.Uint32(hs.Data) - agsmd, err := Model.NewAgentStatusDB() - if err != nil { - return nil, err - } - rst, err := agsmd.ExistRecord() + agsDb, err := Model.NewAgentStatusDB() if err != nil { return nil, err } - if rst { - return nil, fmt.Errorf("Agent Status DB : no Records") - } - records, err := agsmd.SelectAllRecords() + agsDb.InsertRecord(&Model.AgentStatusRecord{ + ID: 0, + UUID: HSProtocol.ByteArrayToHexString(hs.UUID), + Protocol: Model.BinaryToProtocol(hs.ProtocolID), + Status: Model.BinaryToAgentStatus(hs.HealthStatus), + }) + err = agsDb.InsertRecord(&Model.AgentStatusRecord{}) if err != nil { return nil, err } - hs_uuid := string(hs.UUID[:]) - - for _, record := range records { - if record.UUID == hs_uuid { - record.Protocol = Model.BinaryToProtocol(hs.ProtocolID) - err = agsmd.UpdateRecord(&record) - if err != nil { - return nil, err - } - } - } return &HSProtocol.HS{ // HSProtocol.ACK ProtocolID: hs.ProtocolID, @@ -147,12 +136,13 @@ func SEND_AGENT_SYS_INFO(hs *HSProtocol.HS) (*HSProtocol.HS, error) { if err != nil { return nil, err } - Dsys, err := sysDB.Unmarshal(hs.Data) + sysinfo := Model.DsystemInfoDB{} + err = json.Unmarshal(hs.Data, &sysinfo) if err != nil { return nil, err } - err = sysDB.InsertRecord(Dsys) + err = sysDB.InsertRecord(&sysinfo) if err != nil { return nil, err } @@ -171,16 +161,22 @@ func SEND_AGENT_SYS_INFO(hs *HSProtocol.HS) (*HSProtocol.HS, error) { // Command: 5 (0b0000000101) func SEND_AGENT_APP_INFO(hs *HSProtocol.HS) (*HSProtocol.HS, error) { - appDB := Model.ApplicationDB{} - Dapp, err := appDB.Unmarshal(hs.Data) + appDB, err := Model.NewApplicationDB() if err != nil { return nil, err } - err = appDB.InsertRecord(Dapp) + applist, err := appDB.FromJSON(hs.Data) if err != nil { return nil, err } + for _, Dapp := range applist { + err = appDB.InsertRecord(&Dapp) + if err != nil { + return nil, err + } + } + return &HSProtocol.HS{ // HSProtocol.ACK ProtocolID: hs.ProtocolID, Command: HSProtocol.ACK, @@ -246,27 +242,27 @@ func FETCH_INSTRUCTION(hs *HSProtocol.HS) (*HSProtocol.HS, error) { } // Command: 7 (0b0000000111) -func SEND_PROCEDURE_LOG(hs *HSProtocol.HS) (*HSProtocol.HS, error) { - - //hs_uuid := HSProtocol.ByteArrayToHexString(hs.UUID) - - appDB := Model.ApplicationDB{} - Dapp, err := appDB.Unmarshal(hs.Data) - if err != nil { - return nil, err - } - err = appDB.InsertRecord(Dapp) - if err != nil { - return nil, err - } - - return &HSProtocol.HS{ // HSProtocol.ACK - ProtocolID: hs.ProtocolID, - Command: HSProtocol.ACK, - UUID: hs.UUID, - HealthStatus: hs.HealthStatus, - Identification: hs.Identification, - TotalLength: hs.TotalLength, - Data: []byte{}, - }, nil -} +//func SEND_PROCEDURE_LOG(hs *HSProtocol.HS) (*HSProtocol.HS, error) { +// +// hs_uuid := HSProtocol.ByteArrayToHexString(hs.UUID) +// +///* appDB := Model.ApplicationDB{} +// Dapp, err := appDB.Unmarshal(hs.Data) +// if err != nil { +// return nil, err +// } +// err = appDB.InsertRecord(Dapp) +// if err != nil { +// return nil, err +// } +// +// return &HSProtocol.HS{ // HSProtocol.ACK +// ProtocolID: hs.ProtocolID, +// Command: HSProtocol.ACK, +// UUID: hs.UUID, +// HealthStatus: hs.HealthStatus, +// Identification: hs.Identification, +// TotalLength: hs.TotalLength, +// Data: []byte{}, +// }, nil*/ +//} diff --git a/Model/AgentStatus.go b/Model/AgentStatus.go index 2b03446..a1b4ba7 100644 --- a/Model/AgentStatus.go +++ b/Model/AgentStatus.go @@ -167,6 +167,17 @@ func (s *AgentStatusDB) InsertRecord(data *AgentStatusRecord) error { } defer db.Close() + checkQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE uuid = ?`, s.dbName) + var count int + err = db.QueryRow(checkQuery, data.UUID).Scan(&count) + if err != nil { + return err + } + if count > 0 { + // 중복된 항목이 있으면 업데이트 + return s.UpdateRecord(data) + } + query := fmt.Sprintf(`INSERT INTO %s (uuid, status, protocol) VALUES (?, ?, ?)`, s.dbName) stmt, err := db.Prepare(query) if err != nil { @@ -219,8 +230,8 @@ func (s *AgentStatusDB) UpdateRecord(data *AgentStatusRecord) error { } defer db.Close() - query := fmt.Sprintf(`UPDATE %s SET status = ?, protocol = ? WHERE uuid = ?`, s.dbName) - _, err = db.Exec(query, data.Status, data.Protocol, data.UUID) + query := fmt.Sprintf(`UPDATE %s SET status = ? WHERE uuid = ?`, s.dbName) + _, err = db.Exec(query, data.Status, data.UUID) if err != nil { return err } @@ -261,7 +272,6 @@ func (s *AgentStatusDB) DeleteAllRecord() error { return nil } -// ExistRecord checks if at least one record exists in the AgentStatus table. func (s *AgentStatusDB) ExistRecord() (bool, error) { db, err := getDBPtr() if err != nil { diff --git a/Model/ApplicationDB.go b/Model/ApplicationDB.go index 4beb842..9ad950c 100644 --- a/Model/ApplicationDB.go +++ b/Model/ApplicationDB.go @@ -20,25 +20,25 @@ func NewApplicationDB() (*ApplicationDB, error) { } type DapplicationDB struct { - ID int // 내부 ID, 자동 증가 - AgentUUID string - Name string // 제품 이름 - Version string // 제품 버전 - Language string // 제품의 언어 - Vendor string // 제품 공급자 - InstallDate2 string // 설치 날짜 - InstallLocation string // 패키지 설치 위치 - InstallSource string // 설치 소스 위치 - PackageName string // 원래 패키지 이름 - PackageCode string // 패키지 식별자 - RegCompany string // 제품을 사용하는 것으로 등록된 회사 이름 - RegOwner string // 제품을 사용하는 것으로 등록된 사용자 이름 - URLInfoAbout string // 제품에 대한 정보가 제공되는 URL - Description string // 제품 설명 - isDeleted bool - CreateAt time.Time // 레코드 생성 시간 - UpdateAt time.Time // 레코드 업데이트 시간 - deletedAt time.Time + ID int `json:"id"` + AgentUUID string `json:"agent_uuid"` + Name string `json:"name"` + Version string `json:"version"` + Language string `json:"language"` + Vendor string `json:"vendor"` + InstallDate2 string `json:"install_date"` + InstallLocation string `json:"install_location"` + InstallSource string `json:"install_source"` + PackageName string `json:"package_name"` + PackageCode string `json:"package_code"` + RegCompany string `json:"reg_company"` + RegOwner string `json:"reg_owner"` + URLInfoAbout string `json:"url_info_about"` + Description string `json:"description"` + IsDeleted bool `json:"is_deleted"` + CreateAt time.Time `json:"create_at"` + UpdateAt time.Time `json:"update_at"` + DeletedAt time.Time `json:"deleted_at"` } func (a *ApplicationDB) createTable() error { @@ -148,27 +148,41 @@ type Win32_Product struct { } func (a *ApplicationDB) InsertRecord(data *DapplicationDB) error { - // ProductID 가 있는지 확인 후 중복되는 것이 없으면 insert 하기 - + // 데이터베이스 연결 db, err := getDBPtr() if err != nil { return err } defer db.Close() - query := fmt.Sprintf(`INSERT INTO %s ( Name, Version, Language, Vendor, + // PackageCode 중복 확인 쿼리 + checkQuery := fmt.Sprintf(`SELECT COUNT(*) FROM %s WHERE PackageCode = ? AND AgentUUID = ?`, a.dbName) + var count int + err = db.QueryRow(checkQuery, data.PackageCode, data.AgentUUID).Scan(&count) + if err != nil { + return err + } + + if count > 0 { + // 중복된 항목이 있으면 업데이트 + return a.UpdateByPackageCode(data) + } + //fmt.Println("dedbug") + + // 중복된 항목이 없으면 삽입 + query := fmt.Sprintf(`INSERT INTO %s (AgentUUID, Name, Version, Language, Vendor, InstallDate2, InstallLocation, InstallSource, PackageName, PackageCode, RegCompany, - RegOwner, URLInfoAbout, Description ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, a.dbName) + RegOwner, URLInfoAbout, Description) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, a.dbName) stmt, err := db.Prepare(query) - defer stmt.Close() if err != nil { return err } + defer stmt.Close() - _, err = stmt.Exec(&data.Name, &data.Version, &data.Language, &data.Vendor, - &data.InstallDate2, &data.InstallLocation, &data.InstallSource, &data.PackageName, - &data.PackageCode, &data.RegCompany, &data.RegOwner, &data.URLInfoAbout, &data.Description) + _, err = stmt.Exec(data.AgentUUID, data.Name, data.Version, data.Language, data.Vendor, + data.InstallDate2, data.InstallLocation, data.InstallSource, data.PackageName, + data.PackageCode, data.RegCompany, data.RegOwner, data.URLInfoAbout, data.Description) if err != nil { return err @@ -177,23 +191,25 @@ func (a *ApplicationDB) InsertRecord(data *DapplicationDB) error { return nil } -/* -selectRecords()를 통해 반환된 DsystemInfoDB 객체의 값을 수정한 후, -수정된 객체를 updateRecord 함수의 매개변수로 전달합시오 -*/ func (a *ApplicationDB) UpdateByPackageCode(data *DapplicationDB) error { + // 데이터베이스 연결 db, err := getDBPtr() if err != nil { return err } defer db.Close() - query := fmt.Sprintf(`UPDATE %s SET Name = ?, AgentUUID = ?, Version = ?, Language = ?, Vendor = ?, InstallDate2 = ?, InstallLocation = ?, InstallSource = ?, PackageName = ?, RegCompany = ?, RegOwner = ?, URLInfoAbout = ?, Description = ? WHERE PackageCode = ?`, a.dbName) - _, err = db.Exec(query, data.Name, data.AgentUUID, data.Version, data.Language, data.Vendor, data.InstallDate2, data.InstallLocation, data.InstallSource, data.PackageName, data.RegCompany, data.RegOwner, data.URLInfoAbout, data.Description, data.PackageCode) + query := fmt.Sprintf(`UPDATE %s SET Name = ?, AgentUUID = ?, Version = ?, Language = ?, Vendor = ?, + InstallDate2 = ?, InstallLocation = ?, InstallSource = ?, PackageName = ?, RegCompany = ?, + RegOwner = ?, URLInfoAbout = ?, Description = ? WHERE PackageCode = ?`, a.dbName) + + _, err = db.Exec(query, data.Name, data.AgentUUID, data.Version, data.Language, data.Vendor, + data.InstallDate2, data.InstallLocation, data.InstallSource, data.PackageName, + data.RegCompany, data.RegOwner, data.URLInfoAbout, data.Description, data.PackageCode) + if err != nil { return err } - return nil } @@ -219,7 +235,7 @@ func (s *ApplicationDB) SelectByPackageCode(packageCode string) (*DapplicationDB err = row.Scan(&data.ID, &data.Name, &data.AgentUUID, &data.Version, &data.Language, &data.Vendor, &data.InstallDate2, &data.InstallLocation, &data.InstallSource, &data.PackageName, &data.PackageCode, &data.RegCompany, &data.RegOwner, &data.URLInfoAbout, &data.Description, - &data.isDeleted, &data.CreateAt, &data.UpdateAt, &data.deletedAt) + &data.IsDeleted, &data.CreateAt, &data.UpdateAt, &data.DeletedAt) if err != nil { return nil, err @@ -244,6 +260,22 @@ func (s *ApplicationDB) DeleteByPackageCode(packageCode string) error { return nil } +func (s *ApplicationDB) DeleteByAgentUUID(agentUUID string) error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`DELETE FROM %s WHERE AgentUUID = ?`, s.dbName) + _, err = db.Exec(query, agentUUID) + if err != nil { + return err + } + + return nil +} + func (s *ApplicationDB) DeleteAllRecords() error { db, err := getDBPtr() if err != nil { @@ -279,10 +311,10 @@ func (s *ApplicationDB) SelectAllRecords() ([]DapplicationDB, error) { for row.Next() { var data DapplicationDB - err = row.Scan(&data.ID, &data.Name, &data.AgentUUID, &data.Version, &data.Language, &data.Vendor, + err = row.Scan(&data.ID, &data.AgentUUID, &data.Name, &data.Version, &data.Language, &data.Vendor, &data.InstallDate2, &data.InstallLocation, &data.InstallSource, &data.PackageName, &data.PackageCode, &data.RegCompany, &data.RegOwner, &data.URLInfoAbout, &data.Description, - &data.isDeleted, &data.CreateAt, &data.UpdateAt, &data.deletedAt) + &data.IsDeleted, &data.CreateAt, &data.UpdateAt, &data.DeletedAt) if err != nil { return nil, err } @@ -292,14 +324,14 @@ func (s *ApplicationDB) SelectAllRecords() ([]DapplicationDB, error) { return rows, nil } -func (s *ApplicationDB) Unmarshal(data []byte) (*DapplicationDB, error) { - - var Dapp DapplicationDB - err := json.Unmarshal(data, &Dapp) - if err != nil { - fmt.Println("Error unmarshaling JSON:", err) - return nil, err - } +// ToJSON: 구조체를 JSON 바이트로 마샬링 +func (s *ApplicationDB) ToJSON(data []DapplicationDB) ([]byte, error) { + return json.Marshal(data) +} - return &Dapp, nil +// FromJSON: JSON 바이트를 구조체로 언마샬링 +func (s *ApplicationDB) FromJSON(data []byte) ([]DapplicationDB, error) { + var result []DapplicationDB + err := json.Unmarshal(data, &result) + return result, err } diff --git a/Model/OperationLog.go b/Model/OperationLog.go index a3cba3a..5679206 100644 --- a/Model/OperationLog.go +++ b/Model/OperationLog.go @@ -26,6 +26,12 @@ type OperationLogDocument struct { Command string `bson:"command"` // Command 필드로 변경 } +const ( + EXIT_SUCCESS = 1 + EXIT_Unknown = 0 + EXIT_FAIL = -1 +) + type OperationLogDB struct { DBNAME string } diff --git a/Model/SystemInfoDB.go b/Model/SystemInfoDB.go index 4d0124d..050196c 100644 --- a/Model/SystemInfoDB.go +++ b/Model/SystemInfoDB.go @@ -45,7 +45,6 @@ func (s *SystemInfoDB) CreateTable() error { CREATE TABLE IF NOT EXISTS %s ( id INTEGER PRIMARY KEY AUTOINCREMENT, -- 내부 ID, 자동 증가 uuid TEXT NOT NULL unique, -- UUIDv4 - AgentUUID VARCHAR(255), HostName string, OsName string, OsVersion string, diff --git a/db.db b/db.db index 83cca8bdbbbaaa0a13985e561ea3885d5a22a270..8923fc3ad36a19de85da75381dea452b6588068e 100644 GIT binary patch literal 147456 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 diff --git a/main.go b/main.go index 5e335fb..0d70a67 100644 --- a/main.go +++ b/main.go @@ -144,7 +144,6 @@ func HTTPServer() { app.Use(cors.New(cors.Config{ AllowOrigins: []string{"*", "http://localhost/*"}, AllowHeaders: []string{"Origin", "Content-Type", "Accept"}, - //AllowCredentials: true, })) router.SetupAPIRoutes(app) diff --git a/router/api.go b/router/api.go index d7c42d8..6fc61a1 100644 --- a/router/api.go +++ b/router/api.go @@ -51,7 +51,18 @@ func checkInstReq(ctx fiber.Ctx) error { dipt := Core.CommandDispatcher{} ack, err := dipt.Action(hs) if err != nil { + ack := &HSProtocol.HS{ // HSProtocol.ACK + ProtocolID: hs.ProtocolID, + Command: HSProtocol.ERROR_ACK, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + } + rstb, _ := HSMgr.ToBytes(ack) fmt.Println(err) + return ctx.Send(rstb) } rstb, err := HSMgr.ToBytes(ack) diff --git a/view/html/viewdata.html b/view/html/viewdata.html index d281f5f..e3ef69c 100644 --- a/view/html/viewdata.html +++ b/view/html/viewdata.html @@ -130,7 +130,17 @@

Combined Data Tables

+ + + + + + + + + + @@ -225,15 +235,25 @@

Combined Data Tables

data.application.forEach(app => { applicationTable.innerHTML += `
- - - - - - - - - + + + + + + + + + + + + + + + + + + + `; }); @@ -257,17 +277,17 @@

Combined Data Tables

data.system_info.forEach(info => { systemInfoTable.innerHTML += `
- - - - - - - - - - - + + + + + + + + + + + `; }); }); From 443cb361d2a45d2260bd1202b2cfb4879e99dddd Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Wed, 18 Sep 2024 23:01:11 +0900 Subject: [PATCH 22/26] =?UTF-8?q?HTTPS-53=20<=20agent=20uuid=20=EA=B8=B0?= =?UTF-8?q?=EB=B0=98=EC=9C=BC=EB=A1=9C=20=EC=A0=95=EB=B3=B4=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=ED=95=98=EB=8A=94=20api=20=EC=99=84?= =?UTF-8?q?=EC=84=B1=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/CommandDispatcher.go | 57 +++++++++++++++------------ Model/AgentStatus.go | 25 +++++++++++- Model/ApplicationDB.go | 35 +++++++++++++++- Model/OperationLog.go | 2 +- Model/SystemInfoDB.go | 29 ++++++++++++++ Model/nosqldb.go | 12 +++--- db.db | Bin 147456 -> 0 bytes docs/docs.go | 6 +-- docs/swagger.json | 6 +-- docs/swagger.yaml | 6 +-- router/api.go | 6 +-- router/view.go | 81 ++++++++++++++++---------------------- view/html/viewdata.html | 26 ++++++------ 13 files changed, 181 insertions(+), 110 deletions(-) delete mode 100644 db.db diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index 0be5ee9..ceb3d88 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -29,8 +29,8 @@ func (cd *CommandDispatcher) Action(hs *HSProtocol.HS) (*HSProtocol.HS, error) { return SEND_AGENT_APP_INFO(hs) case HSProtocol.FETCH_INSTRUCTION: return FETCH_INSTRUCTION(hs) - //case HSProtocol.SEND_PROCEDURE_LOG: - // return SEND_PROCEDURE_LOG(hs) + case HSProtocol.SEND_PROCEDURE_LOG: + return SEND_PROCEDURE_LOG(hs) } return nil, fmt.Errorf("Invalid Command") @@ -242,27 +242,32 @@ func FETCH_INSTRUCTION(hs *HSProtocol.HS) (*HSProtocol.HS, error) { } // Command: 7 (0b0000000111) -//func SEND_PROCEDURE_LOG(hs *HSProtocol.HS) (*HSProtocol.HS, error) { -// -// hs_uuid := HSProtocol.ByteArrayToHexString(hs.UUID) -// -///* appDB := Model.ApplicationDB{} -// Dapp, err := appDB.Unmarshal(hs.Data) -// if err != nil { -// return nil, err -// } -// err = appDB.InsertRecord(Dapp) -// if err != nil { -// return nil, err -// } -// -// return &HSProtocol.HS{ // HSProtocol.ACK -// ProtocolID: hs.ProtocolID, -// Command: HSProtocol.ACK, -// UUID: hs.UUID, -// HealthStatus: hs.HealthStatus, -// Identification: hs.Identification, -// TotalLength: hs.TotalLength, -// Data: []byte{}, -// }, nil*/ -//} +func SEND_PROCEDURE_LOG(hs *HSProtocol.HS) (*HSProtocol.HS, error) { + + //hs_uuid := HSProtocol.ByteArrayToHexString(hs.UUID) + + logdb, err := Model.NewOperationLogDB() + if err != nil { + return nil, err + } + log := &Model.OperationLogDocument{} + err = json.Unmarshal(hs.Data, &log) + if err != nil { + return nil, err + } + + _, err = logdb.InsertDocument(log) + if err != nil { + return nil, err + } + + return &HSProtocol.HS{ // HSProtocol.ACK + ProtocolID: hs.ProtocolID, + Command: HSProtocol.ACK, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + }, nil +} diff --git a/Model/AgentStatus.go b/Model/AgentStatus.go index a1b4ba7..3f15873 100644 --- a/Model/AgentStatus.go +++ b/Model/AgentStatus.go @@ -1,6 +1,7 @@ package Model import ( + "database/sql" "fmt" "time" ) @@ -193,7 +194,6 @@ func (s *AgentStatusDB) InsertRecord(data *AgentStatusRecord) error { return nil } -// SelectRecords retrieves all records from the AgentStatus table. func (s *AgentStatusDB) SelectAllRecords() ([]AgentStatusRecord, error) { db, err := getDBPtr() if err != nil { @@ -222,6 +222,29 @@ func (s *AgentStatusDB) SelectAllRecords() ([]AgentStatusRecord, error) { return records, nil } +func (s *AgentStatusDB) SelectRecordByUUID(uuid string) ([]AgentStatusRecord, error) { + db, err := getDBPtr() + if err != nil { + return nil, err + } + defer db.Close() + + query := fmt.Sprintf(`SELECT id, uuid, status, protocol, createAt, updateAt FROM %s WHERE uuid = ?`, s.dbName) + row := db.QueryRow(query, uuid) + + var records []AgentStatusRecord + var record AgentStatusRecord + err = row.Scan(&record.ID, &record.UUID, &record.Status, &record.Protocol, &record.CreatedAt, &record.UpdatedAt) + if err != nil { + if err == sql.ErrNoRows { + return nil, nil // Return nil if no record is found + } + return nil, err + } + + return append(records, record), nil +} + // UpdateRecord updates the status and protocol of a record identified by its UUID. func (s *AgentStatusDB) UpdateRecord(data *AgentStatusRecord) error { db, err := getDBPtr() diff --git a/Model/ApplicationDB.go b/Model/ApplicationDB.go index 9ad950c..2ac8c6e 100644 --- a/Model/ApplicationDB.go +++ b/Model/ApplicationDB.go @@ -232,7 +232,7 @@ func (s *ApplicationDB) SelectByPackageCode(packageCode string) (*DapplicationDB if row.Next() == false { return &DapplicationDB{PackageCode: "-1"}, nil } - err = row.Scan(&data.ID, &data.Name, &data.AgentUUID, &data.Version, &data.Language, &data.Vendor, + err = row.Scan(&data.ID, &data.AgentUUID, &data.Name, &data.Version, &data.Language, &data.Vendor, &data.InstallDate2, &data.InstallLocation, &data.InstallSource, &data.PackageName, &data.PackageCode, &data.RegCompany, &data.RegOwner, &data.URLInfoAbout, &data.Description, &data.IsDeleted, &data.CreateAt, &data.UpdateAt, &data.DeletedAt) @@ -283,7 +283,7 @@ func (s *ApplicationDB) DeleteAllRecords() error { } defer db.Close() - query := fmt.Sprintf(`DELETE FROM %s WHERE`) + query := fmt.Sprintf(`DELETE FROM %s WHERE`, s.dbName) _, err = db.Exec(query) if err != nil { return err @@ -324,6 +324,37 @@ func (s *ApplicationDB) SelectAllRecords() ([]DapplicationDB, error) { return rows, nil } +// SelectRecordByUUID retrieves a record from the ApplicationDB table by UUID. +func (s *ApplicationDB) SelectRecordByUUID(uuid string) ([]DapplicationDB, error) { + db, err := getDBPtr() + if err != nil { + return nil, err + } + defer db.Close() + + query := fmt.Sprintf(`SELECT * FROM %s WHERE AgentUUID = ?`, s.dbName) + rows, err := db.Query(query, uuid) + if err != nil { + return nil, err + } + defer rows.Close() + + results := []DapplicationDB{} + for rows.Next() { + var data DapplicationDB + err = rows.Scan(&data.ID, &data.AgentUUID, &data.Name, &data.Version, &data.Language, &data.Vendor, + &data.InstallDate2, &data.InstallLocation, &data.InstallSource, &data.PackageName, + &data.PackageCode, &data.RegCompany, &data.RegOwner, &data.URLInfoAbout, &data.Description, + &data.IsDeleted, &data.CreateAt, &data.UpdateAt, &data.DeletedAt) + if err != nil { + return nil, err + } + results = append(results, data) + } + + return results, nil +} + // ToJSON: 구조체를 JSON 바이트로 마샬링 func (s *ApplicationDB) ToJSON(data []DapplicationDB) ([]byte, error) { return json.Marshal(data) diff --git a/Model/OperationLog.go b/Model/OperationLog.go index 5679206..6b9287a 100644 --- a/Model/OperationLog.go +++ b/Model/OperationLog.go @@ -40,7 +40,7 @@ func NewOperationLogDB() (*OperationLogDB, error) { return &OperationLogDB{DBNAME: "execLog"}, nil } -func (repo *OperationLogDB) InsertDocument(log OperationLogDocument) (*mongo.InsertOneResult, error) { +func (repo *OperationLogDB) InsertDocument(log *OperationLogDocument) (*mongo.InsertOneResult, error) { db, err := getCollectionPtr() if err != nil { return nil, err diff --git a/Model/SystemInfoDB.go b/Model/SystemInfoDB.go index 050196c..deb84cd 100644 --- a/Model/SystemInfoDB.go +++ b/Model/SystemInfoDB.go @@ -218,6 +218,35 @@ func (s *SystemInfoDB) SelectAllRecords() ([]DsystemInfoDB, error) { return rows, nil } +func (s *SystemInfoDB) SelectRecordByUUID(uuid string) ([]DsystemInfoDB, error) { + db, err := getDBPtr() + if err != nil { + return nil, err + } + defer db.Close() + + query := fmt.Sprintf(`SELECT * FROM %s WHERE uuid = ?`, s.dbName) + rows, err := db.Query(query, uuid) + if err != nil { + return nil, err + } + defer rows.Close() + + results := []DsystemInfoDB{} + for rows.Next() { + data := DsystemInfoDB{} + err = rows.Scan(&data.ID, &data.Uuid, &data.HostName, &data.OsName, + &data.OsVersion, &data.Family, &data.Architecture, &data.KernelVersion, + &data.BootTime, &data.CreatedAt, &data.UpdatedAt) + if err != nil { + return nil, err + } + results = append(results, data) + } + + return results, nil +} + /* * 하나 이상의 row 행이 있는지 검사한다. diff --git a/Model/nosqldb.go b/Model/nosqldb.go index 9d18502..aa77437 100644 --- a/Model/nosqldb.go +++ b/Model/nosqldb.go @@ -23,7 +23,7 @@ func getCollectionPtr() (*mongo.Database, error) { ApplyURI("mongodb://" + MONGOID + ":" + MONGOPW + "@uskawjdu.iptime.org:17017/"). // MongoDB URI SetMaxPoolSize(50). // 최대 풀 크기 SetMinPoolSize(10). // 최소 풀 크기 - SetMaxConnIdleTime(30 * time.Second) // 최대 유휴 시간 + SetMaxConnIdleTime(60 * time.Second) // 최대 유휴 시간 //fmt.Println("mongodb://" + MONGOID + ":" + MONGOPW + "@uskawjdu.iptime.org:17017/") // 클라이언트 생성 client, err := mongo.NewClient(clientOptions) @@ -32,11 +32,6 @@ func getCollectionPtr() (*mongo.Database, error) { return nil, err } - err = client.Ping(context.TODO(), nil) - if err != nil { - return nil, fmt.Errorf("failed to connect to MongoDB: %v", err) - } - // 연결 설정 ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel() @@ -50,6 +45,11 @@ func getCollectionPtr() (*mongo.Database, error) { database := client.Database("httpsAgent") + err = client.Ping(context.TODO(), nil) + if err != nil { + return nil, fmt.Errorf("failed to connect to MongoDB: %v", err) + } + // 클라이언트 연결 반환 return database, nil } diff --git a/db.db b/db.db deleted file mode 100644 index 8923fc3ad36a19de85da75381dea452b6588068e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147456 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 Data Tables .then(data => { // Operation Log Table const operationLogTable = document.getElementById('operation-log-table').querySelector('tbody'); - operationLogTable.innerHTML = ` - - - - - - - - - - `; + operationLogTable.innerHTML = ''; + data.operation_log.forEach(log => { + operationLogTable.innerHTML += ` + + + + + + + + + + `; + }); + // Agent Status Table const agentStatusTable = document.getElementById('agent-status-table').querySelector('tbody'); From 5acca4b70dce912214317f8d1bccbebfd59eaf95 Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Wed, 2 Oct 2024 15:30:30 +0900 Subject: [PATCH 23/26] =?UTF-8?q?HTTPS-53=20<=20TCP=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=ED=86=A0=EC=BD=9C=20=EC=A7=80=EC=9B=90=20>?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/CommandDispatcher.go | 2 +- Core/InstructionManager.go | 8 +++- Core/JobManager.go | 69 ----------------------------- Model/AgentStatus.go | 81 +++++++-------------------------- Model/JobData.go | 40 ++++++++--------- Model/OperationLog.go | 20 ++++----- Model/OperationLog_test.go | 91 -------------------------------------- Model/SystemInfoDB.go | 39 ++++++---------- Model/SystemInfoDB_test.go | 81 --------------------------------- docs/docs.go | 2 +- docs/swagger.json | 2 +- docs/swagger.yaml | 2 +- go.mod | 2 +- go.sum | 4 ++ main.go | 43 +++++++++++++----- router/api.go | 10 ++--- 16 files changed, 114 insertions(+), 382 deletions(-) delete mode 100644 Core/JobManager.go delete mode 100644 Model/OperationLog_test.go delete mode 100644 Model/SystemInfoDB_test.go diff --git a/Core/CommandDispatcher.go b/Core/CommandDispatcher.go index ceb3d88..0da2d35 100644 --- a/Core/CommandDispatcher.go +++ b/Core/CommandDispatcher.go @@ -78,7 +78,7 @@ func UPDATE_AGENT_PROTOCOL(hs *HSProtocol.HS) (*HSProtocol.HS, error) { TotalLength: hs.TotalLength, Data: []byte{}, }, nil - } else if (flag == false) && (hs.HealthStatus == uint8(Model.WAIT)) { + } else if (flag == false) && (hs.HealthStatus == uint8(HSProtocol.WAIT)) { agsmd.InsertRecord(&Model.AgentStatusRecord{ UUID: hs_uuid, Status: Model.BinaryToAgentStatus(hs.HealthStatus), diff --git a/Core/InstructionManager.go b/Core/InstructionManager.go index 945d999..5387195 100644 --- a/Core/InstructionManager.go +++ b/Core/InstructionManager.go @@ -54,7 +54,7 @@ func NewInstructionManager() (*InstructionManager, error) { // loadCommands는 주어진 경로에서 모든 YAML 파일을 읽어들여 InstructionData로 변환합니다. func (cm *InstructionManager) loadCommands() error { // 디렉토리 내의 모든 YAML 파일을 찾습니다. - files, err := filepath.Glob(filepath.Join("../CommandDB/", "*.yaml")) + files, err := filepath.Glob(filepath.Join("../HTTPsBAS-Procedures/", "*.yaml")) if err != nil { return fmt.Errorf("failed to read directory: %w", err) } @@ -106,6 +106,10 @@ func (cm *InstructionManager) GetByID(id string) (*InstructionData, bool) { return &command, true } +/** 이전에 쓰고 현재는 사용하지 않는 코드라서 주석처리했습니다. +해당 코드를 지우기전에 허남정 연구원에게 연락주시길 바랍니다. + + //// Insert는 새로운 InstructionData를 삽입하는 함수입니다. //// 이미 동일한 ID가 존재하면 false를 반환하고, 성공적으로 삽입되면 true를 반환합니다. //func (cm *InstructionManager) Insert(command InstructionData) bool { @@ -135,3 +139,5 @@ func (cm *InstructionManager) GetByID(id string) (*InstructionData, bool) { // fmt.Printf("Command with ID %s not found\n", id) // } //} + +*/ diff --git a/Core/JobManager.go b/Core/JobManager.go deleted file mode 100644 index 92a8335..0000000 --- a/Core/JobManager.go +++ /dev/null @@ -1,69 +0,0 @@ -package Core - -// -//import ( -// "fmt" -// "github.com/your/repo/Model" -//) -// -//type JobManager struct { -// jobDB *Model.JobDB -//} -// -//// NewJobManager: JobDB와 연결하고 JobManager 생성 -//func NewJobManager() (*JobManager, error) { -// jobDB, err := Model.NewJobDB() -// if err != nil { -// return nil, err -// } -// -// return &JobManager{jobDB: jobDB}, nil -//} -// -//// InsertData: Model의 InsertJobData 함수를 호출하여 JobData 삽입 -//func (jm *JobManager) InsertData(jobData *Model.JobData) error { -// if len(jobData.AgentUUID) != 32 { -// return fmt.Errorf("AgentUUID is not 32 characters") -// } -// if len(jobData.InstructionUUID) != 32 { -// return fmt.Errorf("InstrwuctionUUID is not 32 characters") -// } -// -// err := jm.jobDB.InsertJobData(jobData) -// if err != nil { -// return err -// } -// return nil -//} -// -//func (jm *JobManager) popData(agentUUID string) (*Model.JobData, error, bool) { -// job, err, exist := jm.getDataByAgentUUID(agentUUID) -// if err != nil { -// return nil, err, exist -// } -// if exist == false { -// return nil, fmt.Errorf("Error! NoRecord"), exist -// } -// -// return job, nil, exist -// -//} -// -//// GetDataByAgentUUID: Model의 GetJobDataByAgentUUID 함수를 호출하여 JobData 조회 -//func (jm *JobManager) getDataByAgentUUID(agentUUID string) (*Model.JobData, error, bool) { -// job, err, exist := jm.jobDB.SelectJobDataByAgentUUID(agentUUID) -// if err != nil { -// return nil, err, exist -// } -// -// return job, nil, exist -//} -// -//// DeleteDataByInstructionUUID: Model의 DeleteJobDataByInstructionUUID 함수를 호출하여 JobData 삭제 -//func (jm *JobManager) deleteDataByInstructionUUID(instructionUUID string) error { -// err := jm.jobDB.DeleteJobDataByInstructionUUID(instructionUUID) -// if err != nil { -// return err -// } -// return nil -//} diff --git a/Model/AgentStatus.go b/Model/AgentStatus.go index 3f15873..a1efbe9 100644 --- a/Model/AgentStatus.go +++ b/Model/AgentStatus.go @@ -3,76 +3,23 @@ package Model import ( "database/sql" "fmt" + "github.com/HTTPs-omma/HTTPsBAS-HSProtocol/HSProtocol" "time" ) -// Protocol 유형을 정의합니다. -type Protocol uint8 - -const ( - TCP Protocol = 0b0001 // TCP 프로토콜 - UDP Protocol = 0b0010 // UDP 프로토콜 - HTTP Protocol = 0b0011 // HTTP 프로토콜 - HTTPS Protocol = 0b0100 // HTTPS 프로토콜 - UnknownProtocol Protocol = 0b0000 // 알 수 없는 프로토콜 -) - -// // Protocol을 문자열로 변환하는 메서드를 구현합니다. -func (p Protocol) String() string { - switch p { - case TCP: - return "TCP" - case UDP: - return "UDP" - case HTTP: - return "HTTP" - case HTTPS: - return "HTTPS" - default: - return "Unknown" - } -} - -// // AgentStatus 유형을 정의합니다. -type AgentStatus int - -const ( - NEW AgentStatus = iota // 동작 중인 상태 - WAIT // 대기 중인 상태 - RUN // 정지 후 사라지기 전의 상태 - DELETED - UNKNOWN -) - -// AgentStatus를 문자열로 변환하는 메서드를 구현합니다. -func (s AgentStatus) String() string { - switch s { - case NEW: - return "NEW" - case RUN: - return "Running" - case WAIT: - return "Waiting" - case DELETED: - return "DELETED" - default: - return "Unknown" - } -} - // Binary 값을 AgentStatus로 변환하는 메서드를 구현합니다. func BinaryToAgentStatus(i uint8) AgentStatus { switch i { case 0b00: - return NEW + return HSProtocol.NEW case 0b01: - return WAIT + return HSProtocol.WAIT case 0b10: - return RUN + return HSProtocol.RUN case 0b11: - return DELETED + return HSProtocol.DELETED default: - return UNKNOWN + return HSProtocol.UNKNOWN } } @@ -80,18 +27,24 @@ func BinaryToAgentStatus(i uint8) AgentStatus { func BinaryToProtocol(i uint8) Protocol { switch i { case 0b0001: - return TCP + return HSProtocol.TCP case 0b0010: - return UDP + return HSProtocol.UDP case 0b0011: - return HTTP + return HSProtocol.HTTP case 0b0100: - return HTTPS + return HSProtocol.HTTPS default: - return UnknownProtocol + return HSProtocol.UNKNOWN } } +// Protocol 유형을 정의합니다. +type Protocol uint8 + +// // AgentStatus 유형을 정의합니다. +type AgentStatus int + type AgentStatusDB struct { dbName string } diff --git a/Model/JobData.go b/Model/JobData.go index ddc9973..07200d0 100644 --- a/Model/JobData.go +++ b/Model/JobData.go @@ -7,11 +7,11 @@ import ( ) type JobData struct { - Id int `json:"id"` - ProcedureID string `json:"procedureID"` - AgentUUID string `json:"agentUUID"` - InstructionUUID string `json:"instructionUUID"` - CreateAt time.Time `json:"createAt"` + Id int `json:"id"` + ProcedureID string `json:"procedureID"` + AgentUUID string `json:"agentUUID"` + MessageUUID string `json:"messageUUID"` + CreateAt time.Time `json:"createAt"` } /** @@ -45,7 +45,7 @@ func (jd *JobDB) createTableIfNotExists() error { id INTEGER PRIMARY KEY AUTOINCREMENT, ProcedureID TEXT, AgentUUID TEXT, - InstructionUUID TEXT, + MessageUUID TEXT, CreateAt DATETIME );` @@ -63,9 +63,9 @@ func (jd *JobDB) InsertJobData(jobData *JobData) error { } defer db.Close() jobData.CreateAt = time.Now() - insertSQL := `INSERT INTO jobs (ProcedureID, AgentUUID, InstructionUUID, CreateAt) + insertSQL := `INSERT INTO jobs (ProcedureID, AgentUUID, MessageUUID, CreateAt) VALUES (?, ?, ?, ?)` - _, err = db.Exec(insertSQL, jobData.ProcedureID, jobData.AgentUUID, jobData.InstructionUUID, jobData.CreateAt) + _, err = db.Exec(insertSQL, jobData.ProcedureID, jobData.AgentUUID, jobData.MessageUUID, jobData.CreateAt) fmt.Println(jobData) if err != nil { return fmt.Errorf("insert job failed: %w", err) @@ -81,7 +81,7 @@ func (jd *JobDB) SelectJobDataByAgentUUID(agentUUID string) (*JobData, error, bo } defer db.Close() - selectSQL := `SELECT id, ProcedureID, AgentUUID, InstructionUUID, CreateAt FROM jobs WHERE AgentUUID = ?` + selectSQL := `SELECT id, ProcedureID, AgentUUID, MessageUUID, CreateAt FROM jobs WHERE AgentUUID = ?` rows, err := db.Query(selectSQL, agentUUID) if err != nil { return nil, err, false @@ -93,7 +93,7 @@ func (jd *JobDB) SelectJobDataByAgentUUID(agentUUID string) (*JobData, error, bo } var job *JobData = &JobData{} - err = rows.Scan(&job.ProcedureID, &job.Id, &job.AgentUUID, &job.InstructionUUID, &job.CreateAt) // 첫 행에만 적용 + err = rows.Scan(&job.ProcedureID, &job.Id, &job.AgentUUID, &job.MessageUUID, &job.CreateAt) // 첫 행에만 적용 if err != nil { return nil, err, true } @@ -109,7 +109,7 @@ func (jd *JobDB) SelectAllJobData() ([]JobData, error) { } defer db.Close() - selectSQL := `SELECT id, ProcedureID, AgentUUID, InstructionUUID, CreateAt FROM jobs` + selectSQL := `SELECT id, ProcedureID, AgentUUID, MessageUUID, CreateAt FROM jobs` rows, err := db.Query(selectSQL) defer rows.Close() @@ -123,7 +123,7 @@ func (jd *JobDB) SelectAllJobData() ([]JobData, error) { jobs := []JobData{} var job_init *JobData = &JobData{} - err = rows.Scan(&job_init.Id, &job_init.ProcedureID, &job_init.AgentUUID, &job_init.InstructionUUID, &job_init.CreateAt) // 첫 행에만 적용 + err = rows.Scan(&job_init.Id, &job_init.ProcedureID, &job_init.AgentUUID, &job_init.MessageUUID, &job_init.CreateAt) // 첫 행에만 적용 if err != nil { return nil, err } @@ -131,7 +131,7 @@ func (jd *JobDB) SelectAllJobData() ([]JobData, error) { for rows.Next() == true { var job *JobData = &JobData{} - err = rows.Scan(&job.Id, &job.ProcedureID, &job.AgentUUID, &job.InstructionUUID, &job.CreateAt) // 첫 행에만 적용 + err = rows.Scan(&job.Id, &job.ProcedureID, &job.AgentUUID, &job.MessageUUID, &job.CreateAt) // 첫 행에만 적용 if err != nil { return nil, err } @@ -150,7 +150,7 @@ func (jd *JobDB) PopbyAgentUUID(agentUUID string) (*JobData, error, bool) { // 쿼리문 수정: WHERE 절을 추가하고 ORDER BY를 사용하여 CreateAt을 기준으로 내림차순 정렬 selectSQL := ` - SELECT id, ProcedureID, AgentUUID, InstructionUUID, CreateAt + SELECT id, ProcedureID, AgentUUID, MessageUUID, CreateAt FROM jobs WHERE AgentUUID = ? ORDER BY CreateAt DESC @@ -161,7 +161,7 @@ func (jd *JobDB) PopbyAgentUUID(agentUUID string) (*JobData, error, bool) { row := db.QueryRow(selectSQL, agentUUID) var job JobData - err = row.Scan(&job.Id, &job.ProcedureID, &job.AgentUUID, &job.InstructionUUID, &job.CreateAt) + err = row.Scan(&job.Id, &job.ProcedureID, &job.AgentUUID, &job.MessageUUID, &job.CreateAt) if err != nil { if err == sql.ErrNoRows { // 일치하는 행이 없는 경우 @@ -179,16 +179,16 @@ func (jd *JobDB) PopbyAgentUUID(agentUUID string) (*JobData, error, bool) { return &job, nil, true } -// DeleteJobDataByInstructionUUID: InstructionUUID 기반으로 JobData 삭제 -func (jd *JobDB) DeleteJobDataByInstructionUUID(instructionUUID string) error { +// DeleteJobDataByMessageUUID: MessageUUID 기반으로 JobData 삭제 +func (jd *JobDB) DeleteJobDataByMessageUUID(messageUUID string) error { db, err := getDBPtr() if err != nil { return err } defer db.Close() - deleteSQL := `DELETE FROM jobs WHERE InstructionUUID = ?` - _, err = db.Exec(deleteSQL, instructionUUID) + deleteSQL := `DELETE FROM jobs WHERE MessageUUID = ?` + _, err = db.Exec(deleteSQL, messageUUID) if err != nil { return fmt.Errorf("delete job failed: %w", err) } @@ -210,7 +210,7 @@ func (jd *JobDB) DeleteJobDataById(id int) error { return nil } -// DeleteJobDataByInstructionUUID: InstructionUUID 기반으로 JobData 삭제 +// DeleteJobDataByMessageUUID: MessageUUID 기반으로 JobData 삭제 func (jd *JobDB) DeleteAllJobData() error { db, err := getDBPtr() if err != nil { diff --git a/Model/OperationLog.go b/Model/OperationLog.go index 6b9287a..aebc74f 100644 --- a/Model/OperationLog.go +++ b/Model/OperationLog.go @@ -16,14 +16,14 @@ import ( // OperationLogDocument 구조체 정의 type OperationLogDocument struct { - ID primitive.ObjectID `bson:"_id,omitempty"` - AgentUUID string `bson:"agentUUID"` - ProcedureID string `bson:"procedureID"` - InstructionUUID string `bson:"instructionUUID"` - ConductAt time.Time `bson:"conductAt"` - ExitCode int `bson:"exitCode"` - Log string `bson:"log"` - Command string `bson:"command"` // Command 필드로 변경 + ID primitive.ObjectID `bson:"_id,omitempty"` + AgentUUID string `bson:"agentUUID"` + ProcedureID string `bson:"procedureID"` + MessageUUID string `bson:"messageUUID"` + ConductAt time.Time `bson:"conductAt"` + ExitCode int `bson:"exitCode"` + Log string `bson:"log"` + Command string `bson:"command"` // Command 필드로 변경 } const ( @@ -65,7 +65,7 @@ func (repo *OperationLogDB) SelectDocumentById(id string) (*OperationLogDocument ptrdb := db.Collection(repo.DBNAME) var OperationLogDocument OperationLogDocument - filter := bson.M{"instructionUUID": id} + filter := bson.M{"messageUUID": id} err = ptrdb.FindOne(context.TODO(), filter).Decode(&OperationLogDocument) if err != nil { @@ -114,7 +114,7 @@ func (repo *OperationLogDB) UpdateDocumentByInstID(id string, updateData bson.M) } ptrdb := db.Collection(repo.DBNAME) - filter := bson.M{"instructionUUID": id} + filter := bson.M{"messageUUID": id} update := bson.M{ "$set": updateData, } diff --git a/Model/OperationLog_test.go b/Model/OperationLog_test.go deleted file mode 100644 index 87cc02f..0000000 --- a/Model/OperationLog_test.go +++ /dev/null @@ -1,91 +0,0 @@ -package Model - -import ( - "fmt" - "github.com/joho/godotenv" - "log" - "testing" - "time" -) - -func TestInsertDocument(t *testing.T) { - tests := []struct { - name string - log OperationLogDocument - }{ - { - name: "Insert valid document", - log: OperationLogDocument{ - AgentUUID: "agent-123", - ProcedureID: "tech-456", - InstructionUUID: "msg-789", - ConductAt: time.Now(), - ExitCode: 0, - Log: "Test log message", - Command: "Test command", - }, - }, - } - - for _, tt := range tests { - - // MongoDB 클라이언트 옵션 설정 - err := godotenv.Load(".env") - if err != nil { - log.Fatal("Error loading .env file") - } - - t.Run(tt.name, func(t *testing.T) { - db, err := NewOperationLogDB() - if err != nil { - log.Fatal("에러: ", err) - } - - // insertDocument 호출 - result, err := db.InsertDocument(tt.log) - if err != nil { - t.Errorf("insertDocument() 에러: %v", err) - } - - // 결과 ID가 있는지 확인 - if result == nil || result.InsertedID == nil { - t.Errorf("insertDocument() 결과가 유효하지 않습니다.") - } else { - t.Logf("삽입된 문서 ID: %v", result.InsertedID) - } - - log, err := db.SelectDocumentById(tt.log.InstructionUUID) - if err != nil { - t.Fatalf("select 오류") - } - fmt.Printf("성공 : " + log.InstructionUUID) - - //rst2, err := db.UpdateDocumentByInstID(tt.log.InstructionUUID, - //&OperationLogDocument{ - // AgentUUID: "agent-123", - // ProcedureID: "tech-456", - // InstructionUUID: "msg-789", - // ConductAt: time.Now(), - // ExitCode: 0, - // Log: "Test log message", - // Command: "Test command", - //}) - //if err == nil { - // t.Fatalf("update 오류") - //} - - rst, err := db.DeleteDocumentByInstID(tt.log.InstructionUUID) - if err != nil { - t.Errorf("DeleteDocumentByInstID() 에러: %v", err) - } - // 결과 ID가 있는지 확인 - if rst == nil || rst.DeletedCount == 0 { - t.Errorf("DeleteDocument() 결과가 유효하지 않습니다.") - } else { - t.Logf("정상적으로 삭제됨") - //t.Logf("삭제된 문서 ID: %v", rst.) - } - - }) - } -} diff --git a/Model/SystemInfoDB.go b/Model/SystemInfoDB.go index deb84cd..8fd63a8 100644 --- a/Model/SystemInfoDB.go +++ b/Model/SystemInfoDB.go @@ -21,6 +21,8 @@ type DsystemInfoDB struct { Architecture string `json:"architecture"` KernelVersion string `json:"kernel_version"` BootTime time.Time `json:"boot_time"` + IP string `json:"ip"` // IP 추가 + MAC string `json:"mac"` // MAC 추가 CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } @@ -52,6 +54,8 @@ func (s *SystemInfoDB) CreateTable() error { Architecture string, KernelVersion string, BootTime DATETIME, + IP string, -- IP 추가 + MAC string, -- MAC 추가 createAt DATETIME DEFAULT CURRENT_TIMESTAMP, updateAt DATETIME DEFAULT CURRENT_TIMESTAMP ); @@ -102,21 +106,16 @@ func (s *SystemInfoDB) InsertRecord(data *DsystemInfoDB) error { } defer db.Close() - query := fmt.Sprintf(`INSERT INTO %s (uuid, HostName, - OsName, OsVersion, Family, Architecture, KernelVersion, - BootTime) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, s.dbName) + query := fmt.Sprintf(`INSERT INTO %s (uuid, HostName, OsName, OsVersion, Family, Architecture, KernelVersion, BootTime, IP, MAC) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, s.dbName) stmt, err := db.Prepare(query) - defer stmt.Close() + if err != nil { return err } - _, err = stmt.Exec(data.Uuid, data.HostName, data.OsName, - data.OsVersion, data.Family, data.Architecture, - data.KernelVersion, data.BootTime) - //fmt.Println(rst.LastInsertId()) - //fmt.Println("debug=-===============") + _, err = stmt.Exec(data.Uuid, data.HostName, data.OsName, data.OsVersion, data.Family, data.Architecture, data.KernelVersion, data.BootTime, data.IP, data.MAC) if err != nil { return err @@ -125,10 +124,6 @@ func (s *SystemInfoDB) InsertRecord(data *DsystemInfoDB) error { return nil } -/* -selectRecords()를 통해 반환된 DsystemInfoDB 객체의 값을 수정한 후, -수정된 객체를 updateRecord 함수의 매개변수로 전달합시오 -*/ func (s *SystemInfoDB) UpdateRecord(data *DsystemInfoDB) error { db, err := getDBPtr() if err != nil { @@ -146,8 +141,8 @@ func (s *SystemInfoDB) UpdateRecord(data *DsystemInfoDB) error { row := rows[0] data.Uuid = row.Uuid - query := fmt.Sprintf(`UPDATE %s SET HostName = ?, OsName = ?, OsVersion = ?, Family = ?, Architecture = ?, KernelVersion = ?, BootTime = ?`, s.dbName) - _, err = db.Exec(query, data.HostName, data.OsName, data.OsVersion, data.Family, data.Architecture, data.KernelVersion, data.BootTime) + query := fmt.Sprintf(`UPDATE %s SET HostName = ?, OsName = ?, OsVersion = ?, Family = ?, Architecture = ?, KernelVersion = ?, BootTime = ?, IP = ?, MAC = ?`, s.dbName) + _, err = db.Exec(query, data.HostName, data.OsName, data.OsVersion, data.Family, data.Architecture, data.KernelVersion, data.BootTime, data.IP, data.MAC) if err != nil { return err } @@ -178,7 +173,7 @@ func (s *SystemInfoDB) DeleteAllRecord() error { } defer db.Close() - query := fmt.Sprintf(`DELETE FROM %s WHERE`) + query := fmt.Sprintf(`DELETE FROM %s`, s.dbName) _, err = db.Exec(query) if err != nil { return err @@ -206,9 +201,7 @@ func (s *SystemInfoDB) SelectAllRecords() ([]DsystemInfoDB, error) { for row.Next() { var data DsystemInfoDB - err = row.Scan(&data.ID, &data.Uuid, &data.HostName, &data.OsName, - &data.OsVersion, &data.Family, &data.Architecture, &data.KernelVersion, - &data.BootTime, &data.CreatedAt, &data.UpdatedAt) + err = row.Scan(&data.ID, &data.Uuid, &data.HostName, &data.OsName, &data.OsVersion, &data.Family, &data.Architecture, &data.KernelVersion, &data.BootTime, &data.IP, &data.MAC, &data.CreatedAt, &data.UpdatedAt) if err != nil { return nil, err } @@ -235,9 +228,7 @@ func (s *SystemInfoDB) SelectRecordByUUID(uuid string) ([]DsystemInfoDB, error) results := []DsystemInfoDB{} for rows.Next() { data := DsystemInfoDB{} - err = rows.Scan(&data.ID, &data.Uuid, &data.HostName, &data.OsName, - &data.OsVersion, &data.Family, &data.Architecture, &data.KernelVersion, - &data.BootTime, &data.CreatedAt, &data.UpdatedAt) + err = rows.Scan(&data.ID, &data.Uuid, &data.HostName, &data.OsName, &data.OsVersion, &data.Family, &data.Architecture, &data.KernelVersion, &data.BootTime, &data.IP, &data.MAC, &data.CreatedAt, &data.UpdatedAt) if err != nil { return nil, err } @@ -247,10 +238,6 @@ func (s *SystemInfoDB) SelectRecordByUUID(uuid string) ([]DsystemInfoDB, error) return results, nil } -/* -* -하나 이상의 row 행이 있는지 검사한다. -*/ func (s *SystemInfoDB) ExistRecord() (bool, error) { db, err := getDBPtr() if err != nil { diff --git a/Model/SystemInfoDB_test.go b/Model/SystemInfoDB_test.go deleted file mode 100644 index cbca6a5..0000000 --- a/Model/SystemInfoDB_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package Model - -import ( - "fmt" - "github.com/stretchr/testify/assert" - "testing" -) - -type sqlite_master struct { - Type string - name string - tbl_name string - rootpage string - sql string -} - -func TestSystemInfoDB_createTable(t *testing.T) { - tests := []struct { - name string - wantErr bool - }{ - {name: "create DB test"}, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var err error - s := NewSystemInfoDB() - s.CreateTable() - if err != nil { - t.Fatalf(s.dbName + " : DB를 생성할 수 없습니다. \n" + err.Error()) - } - - // ========== 검증 ============= - dbPtr, err := getDBPtr() - if err != nil { - t.Fatalf(s.dbName + " : DB 포인터를 가져올 수 없습니다. getDBPtr() 함수 오류\n" + err.Error()) - } - - query := fmt.Sprintf("select * from sqlite_master where name = '%s'", s.dbName) - - dsys := &sqlite_master{} - - rst := dbPtr.QueryRow(query).Scan(&dsys.Type, &dsys.name, &dsys.tbl_name, &dsys.rootpage, &dsys.sql) - if rst != nil { - t.Fatalf(s.dbName + " : 생성된 테이블이 존재하지 않습니다.") - } - assert.Equal(t, dsys.name, s.dbName) - - }) - } -} - -func TestNewSystemInfoDB_selectRecord(t *testing.T) { - type fields struct { - dbName string - } - tests := []struct { - name string - fields fields - wantErr bool - }{ - {name: "Select Record in DB"}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var err error - s := NewSystemInfoDB() - - data, err := s.SelectRecords() - - if err != nil { - t.Fatalf(s.dbName + " : select 오류. Query 재 확인 \n" + err.Error()) - } - - assert.Equal(t, 1, len(data), "Row를 하나 이상 채우고 재시도를 하시오") - fmt.Println("sql select result : \n", data) - - }) - } -} diff --git a/docs/docs.go b/docs/docs.go index 5ef150b..d77a6a3 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -57,7 +57,7 @@ const docTemplate = `{ "type": "string", "default": "09a4e53c7a1c4b4e9a519f36df29d8a2" }, - "instructionUUID": { + "messageUUID": { "type": "string", "default": "32a2833486414af9bc4596caef585538" }, diff --git a/docs/swagger.json b/docs/swagger.json index 4502473..a242eed 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -51,7 +51,7 @@ "type": "string", "default": "09a4e53c7a1c4b4e9a519f36df29d8a2" }, - "instructionUUID": { + "messageUUID": { "type": "string", "default": "32a2833486414af9bc4596caef585538" }, diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 70e229b..c4627bb 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -5,7 +5,7 @@ definitions: agentUUID: default: 09a4e53c7a1c4b4e9a519f36df29d8a2 type: string - instructionUUID: + messageUUID: default: 32a2833486414af9bc4596caef585538 type: string procedureID: diff --git a/go.mod b/go.mod index ccba599..ea7746f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/your/repo go 1.23.0 require ( - github.com/HTTPs-omma/HTTPsBAS-HSProtocol v1.0.9 + github.com/HTTPs-omma/HTTPsBAS-HSProtocol v1.0.12 github.com/gin-gonic/gin v1.10.0 github.com/gofiber/fiber/v3 v3.0.0-beta.3 github.com/joho/godotenv v1.5.1 diff --git a/go.sum b/go.sum index 8d2d081..52d77b5 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,9 @@ github.com/HTTPs-omma/HTTPsBAS-HSProtocol v1.0.9 h1:LmGvK4r5RyPb3QaJ//3eqmmufu3W/aikssoWsmQLHhw= github.com/HTTPs-omma/HTTPsBAS-HSProtocol v1.0.9/go.mod h1:7Kv1PDaclTyg/VJ3xPahHfJiYF1GqXIWsbYlGKlUV2c= +github.com/HTTPs-omma/HTTPsBAS-HSProtocol v1.0.11 h1:vHgJG5BhEyxfbNZzXw1DXyQh6x9OU5jIsSHcVRXH+cA= +github.com/HTTPs-omma/HTTPsBAS-HSProtocol v1.0.11/go.mod h1:7Kv1PDaclTyg/VJ3xPahHfJiYF1GqXIWsbYlGKlUV2c= +github.com/HTTPs-omma/HTTPsBAS-HSProtocol v1.0.12 h1:6PXYMZk1DCBQnbiasXXNj2My5p827wFyvP0QZX438Vw= +github.com/HTTPs-omma/HTTPsBAS-HSProtocol v1.0.12/go.mod h1:7Kv1PDaclTyg/VJ3xPahHfJiYF1GqXIWsbYlGKlUV2c= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= diff --git a/main.go b/main.go index 0d70a67..d6c1c6b 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,6 @@ package main import ( - "bytes" "fmt" "github.com/HTTPs-omma/HTTPsBAS-HSProtocol/HSProtocol" cors2 "github.com/gin-contrib/cors" @@ -11,6 +10,7 @@ import ( "github.com/joho/godotenv" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" + "github.com/your/repo/Core" _ "github.com/your/repo/docs" "github.com/your/repo/router" "net" @@ -109,18 +109,41 @@ func handleTCPConnection(conn net.Conn) { hs, err := HSMgr.Parsing(buffer) if err != nil { fmt.Println("Error parsing:", err) - continue - } - - if hs.Command == 0b0000000110 { // payload 를 받아옴 - conn.Write([]byte(testCommand)) + ack := &HSProtocol.HS{ // HSProtocol.ACK + ProtocolID: hs.ProtocolID, + Command: HSProtocol.ERROR_ACK, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + } + rstb, _ := HSMgr.ToBytes(ack) + conn.Write(rstb) + return } - if hs.Command == 0b0000000111 { // 실행 결과를 작성함. - msg := bytes.ReplaceAll(hs.Data, []byte{0x00}, []byte{}) - fmt.Println("Log : ", string(msg)) + //fmt.Println("hs.uuid : ", hs.UUID) + dipt := Core.CommandDispatcher{} + ack, err := dipt.Action(hs) + if err != nil { + ack := &HSProtocol.HS{ // HSProtocol.ACK + ProtocolID: hs.ProtocolID, + Command: HSProtocol.ERROR_ACK, + UUID: hs.UUID, + HealthStatus: hs.HealthStatus, + Identification: hs.Identification, + TotalLength: hs.TotalLength, + Data: []byte{}, + } + rstb, _ := HSMgr.ToBytes(ack) + fmt.Println(err) + conn.Write(rstb) + return } - + rstb, err := HSMgr.ToBytes(ack) + conn.Write(rstb) + return } } diff --git a/router/api.go b/router/api.go index 3a2d42d..5d28433 100644 --- a/router/api.go +++ b/router/api.go @@ -12,9 +12,9 @@ import ( // swagger:parameters Request type InstructionD struct { - ProcedureID string `json:"procedureID" default:"P_DefenseEvasion_Kimsuky_001"` - AgentUUID string `json:"agentUUID" default:"09a4e53c7a1c4b4e9a519f36df29d8a2"` - InstructionUUID string `json:"instructionUUID" default:"32a2833486414af9bc4596caef585538"` + ProcedureID string `json:"procedureID" default:"P_DefenseEvasion_Kimsuky_001"` + AgentUUID string `json:"agentUUID" default:"09a4e53c7a1c4b4e9a519f36df29d8a2"` + MessageUUID string `json:"messageUUID" default:"32a2833486414af9bc4596caef585538"` } // @title ManagingServer API @@ -88,13 +88,13 @@ func postInst(ctx fiber.Ctx) error { if err != nil { return ctx.Send([]byte(err.Error())) } - //fmt.Println("test : ", InstD.ProcedureID, InstD.AgentUUID, InstD.InstructionUUID) + //fmt.Println("test : ", InstD.ProcedureID, InstD.AgentUUID, InstD.MessageUUID) err = jobdb.InsertJobData(&Model.JobData{ 0, InstD.ProcedureID, InstD.AgentUUID, - InstD.InstructionUUID, + InstD.MessageUUID, time.Now(), }) if err != nil { From 86369bfd838d984d4ef1662ecdce7327ccc2fd4c Mon Sep 17 00:00:00 2001 From: CherryPichu Date: Wed, 2 Oct 2024 15:33:58 +0900 Subject: [PATCH 24/26] =?UTF-8?q?tcp=20=EC=A7=80=EC=9B=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/vcs.xml | 2 +- CommandDB | 1 - HTTPsBAS-Procedures | 1 + Model/ProgrameNameDB.go | 211 ++++++++++++++++++++++++++++++++++++++++ Model/test.py | 2 +- db.db | Bin 0 -> 147456 bytes view/html/viewdata.html | 8 +- 7 files changed, 218 insertions(+), 7 deletions(-) delete mode 160000 CommandDB create mode 160000 HTTPsBAS-Procedures create mode 100644 Model/ProgrameNameDB.go create mode 100644 db.db diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 7575a9f..c5f4aea 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,6 +2,6 @@ - + \ No newline at end of file diff --git a/CommandDB b/CommandDB deleted file mode 160000 index 21c2bd9..0000000 --- a/CommandDB +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 21c2bd9a6949a2090bb810fe228fdb6ec40dc659 diff --git a/HTTPsBAS-Procedures b/HTTPsBAS-Procedures new file mode 160000 index 0000000..b24c69f --- /dev/null +++ b/HTTPsBAS-Procedures @@ -0,0 +1 @@ +Subproject commit b24c69f396d4e20031555f48c9ed5e1554184ba5 diff --git a/Model/ProgrameNameDB.go b/Model/ProgrameNameDB.go new file mode 100644 index 0000000..7e13a47 --- /dev/null +++ b/Model/ProgrameNameDB.go @@ -0,0 +1,211 @@ +package Model + +import ( + "encoding/json" + "fmt" + "time" +) + +type ProgramsDB struct { + dbName string +} + +func NewProgramsDB() (*ProgramsDB, error) { + db := &ProgramsDB{dbName: "Programs"} + err := db.CreateTable() + if err != nil { + return nil, err + } + return db, nil +} + +type ProgramsRecord struct { + ID int `json:"id"` + AgentUUID string `json:"agent_uuid"` + FileName string `json:"file_name"` + CreateAt time.Time `json:"create_at"` + UpdateAt time.Time `json:"update_at"` + DeletedAt time.Time `json:"deleted_at"` +} + +func (a *ProgramsDB) CreateTable() error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + sqlStmt := ` + CREATE TABLE IF NOT EXISTS %s ( + id INTEGER PRIMARY KEY AUTOINCREMENT, -- 내부 ID, 자동 증가 + AgentUUID VARCHAR(255), + FileName VARCHAR(255), + createAt DATETIME DEFAULT CURRENT_TIMESTAMP, -- 레코드 생성 시간 + updateAt DATETIME DEFAULT CURRENT_TIMESTAMP, -- 레코드 업데이트 시간 + deletedAt DATETIME DEFAULT CURRENT_TIMESTAMP -- 제거된 시간 + ); + ` + sqlStmt = fmt.Sprintf(sqlStmt, a.dbName) + + _, err = db.Exec(sqlStmt) + if err != nil { + return err + } + + sqlModifyTrigger := fmt.Sprintf(` + CREATE TRIGGER IF NOT EXISTS update_ModificationTime + AFTER UPDATE ON %s + FOR EACH ROW + BEGIN + UPDATE %s SET + updateAt = CURRENT_TIMESTAMP + WHERE id = NEW.id; + END; + `, a.dbName, a.dbName) + + _, err = db.Exec(sqlModifyTrigger) + if err != nil { + return err + } + + return nil +} + +// InsertRecord: 레코드 삽입 +func (a *ProgramsDB) InsertRecord(agentUUID string, fileName string) error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`INSERT INTO %s (AgentUUID, FileName) VALUES (?, ?)`, a.dbName) + _, err = db.Exec(query, agentUUID, fileName) + if err != nil { + return err + } + + return nil +} + +// SelectAllRecords: 모든 레코드를 선택 +func (a *ProgramsDB) SelectAllRecords() ([]ProgramsRecord, error) { + db, err := getDBPtr() + if err != nil { + return nil, err + } + defer db.Close() + + query := fmt.Sprintf(`SELECT id, AgentUUID, FileName, createAt, updateAt, deletedAt FROM %s`, a.dbName) + rows, err := db.Query(query) + if err != nil { + return nil, err + } + defer rows.Close() + + var records []ProgramsRecord + for rows.Next() { + var record ProgramsRecord + err = rows.Scan(&record.ID, &record.AgentUUID, &record.FileName, &record.CreateAt, &record.UpdateAt, &record.DeletedAt) + if err != nil { + return nil, err + } + records = append(records, record) + } + + return records, nil +} + +// SelectRecordsByUUID: 특정 AgentUUID에 따른 레코드를 선택 +func (a *ProgramsDB) SelectRecordsByUUID(agentUUID string) ([]ProgramsRecord, error) { + db, err := getDBPtr() // 데이터베이스 연결 + if err != nil { + return nil, err + } + defer db.Close() + + // 쿼리문 작성 (AgentUUID에 따라 필터링) + query := fmt.Sprintf(`SELECT id, AgentUUID, FileName, createAt, updateAt, deletedAt FROM %s WHERE AgentUUID = ?`, a.dbName) + rows, err := db.Query(query, agentUUID) + if err != nil { + return nil, err + } + defer rows.Close() + + var records []ProgramsRecord + for rows.Next() { + var record ProgramsRecord + // 각 필드의 값을 스캔하여 구조체에 저장 + err = rows.Scan(&record.ID, &record.AgentUUID, &record.FileName, &record.CreateAt, &record.UpdateAt, &record.DeletedAt) + if err != nil { + return nil, err + } + records = append(records, record) + } + + return records, nil +} + +// UpdateRecordByID: ID를 기준으로 레코드 업데이트 +func (a *ProgramsDB) UpdateRecordByID(id int, newFileName string) error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`UPDATE %s SET FileName = ?, updateAt = ? WHERE id = ?`, a.dbName) + _, err = db.Exec(query, newFileName, time.Now(), id) + if err != nil { + return err + } + + return nil +} + +// DeleteRecordByID: ID를 기준으로 레코드 삭제 +func (a *ProgramsDB) DeleteRecordByID(id int) error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`DELETE FROM %s WHERE id = ?`, a.dbName) + _, err = db.Exec(query, id) + if err != nil { + return err + } + + return nil +} + +func (a *ProgramsDB) DeleteAllRecords() error { + db, err := getDBPtr() + if err != nil { + return err + } + defer db.Close() + + query := fmt.Sprintf(`DELETE FROM %s`, a.dbName) + _, err = db.Exec(query) + if err != nil { + return err + } + + return nil +} + +// ToJSON: ProgramNameDB 레코드 리스트를 JSON 바이트로 변환 +func (s *ProgramsDB) ToJSON(data []ProgramsRecord) ([]byte, error) { + // JSON 마샬링하여 []byte로 반환 + return json.Marshal(data) +} + +// FromJSON: JSON 바이트를 ProgramNameDB 레코드 리스트로 변환 +func (s *ProgramsDB) FromJSON(data []byte) ([]ProgramsRecord, error) { + var result []ProgramsRecord + // JSON 언마샬링하여 구조체로 변환 + err := json.Unmarshal(data, &result) + return result, err +} diff --git a/Model/test.py b/Model/test.py index c224ddf..c973b34 100644 --- a/Model/test.py +++ b/Model/test.py @@ -8,7 +8,7 @@ data = { "agentUUID": "12342", "procedureID": "P_Collection_Kimsuky_001", - "instructionUUID": "f5556669-ffbe-4d24-b833-fc9888fdeaef" + "messageUUID": "f5556669-ffbe-4d24-b833-fc9888fdeaef" } # 헤더 설정 diff --git a/db.db b/db.db new file mode 100644 index 0000000000000000000000000000000000000000..524d8d26e8a0a3d205e1c7eebe0a3b2101e59d50 GIT binary patch literal 147456 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 literal 0 HcmV?d00001 diff --git a/view/html/viewdata.html b/view/html/viewdata.html index d8302f6..3543dba 100644 --- a/view/html/viewdata.html +++ b/view/html/viewdata.html @@ -81,7 +81,7 @@

Combined Data Tables

- + @@ -159,7 +159,7 @@

Combined Data Tables

- + @@ -209,7 +209,7 @@

Combined Data Tables

- + @@ -270,7 +270,7 @@

Combined Data Tables

- + `; }); From 9e6e2653f0c6d7ec8f55effbde1072e559af901a Mon Sep 17 00:00:00 2001 From: HeoNamJung Date: Wed, 2 Oct 2024 16:02:25 +0900 Subject: [PATCH 25/26] merge --- HTTPsBAS-Procedures | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HTTPsBAS-Procedures b/HTTPsBAS-Procedures index b24c69f..0534286 160000 --- a/HTTPsBAS-Procedures +++ b/HTTPsBAS-Procedures @@ -1 +1 @@ -Subproject commit b24c69f396d4e20031555f48c9ed5e1554184ba5 +Subproject commit 05342868c65c4d9b1b51ed1269926c873791148d From 5eb2dd40d15d601ea503c01af21ab8c737228bc5 Mon Sep 17 00:00:00 2001 From: HeoNamJung Date: Wed, 2 Oct 2024 16:11:43 +0900 Subject: [PATCH 26/26] merge --- HTTPsBAS-Procedures | 1 - 1 file changed, 1 deletion(-) delete mode 160000 HTTPsBAS-Procedures diff --git a/HTTPsBAS-Procedures b/HTTPsBAS-Procedures deleted file mode 160000 index 0534286..0000000 --- a/HTTPsBAS-Procedures +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 05342868c65c4d9b1b51ed1269926c873791148d
ID ProcedureID AgentUUID InstructionUUID
${job.ProcedureID}${job.AgentUUID}${job.InstructionUUID}${new Date(job.CreatedAt).toLocaleString()}${job.id}${job.procedureID}${job.agentUUID}${job.instructionUUID}${new Date(job.createdAt).toLocaleString()}
Vendor InstallDate InstallLocationInstallSourcePackageNamePackageCodeRegCompanyRegOwnerURLInfoAbout DescriptionIsDeletedCreateAtUpdateAtDeletedAt
${app.ID}${app.AgentUUID}${app.Name}${app.Version}${app.Language}${app.Vendor}${app.InstallDate2}${app.InstallLocation}${app.Description}${app.id}${app.agent_uuid}${app.name}${app.version}${app.language}${app.vendor}${app.install_date}${app.install_location}${app.install_source}${app.package_name}${app.package_code}${app.reg_company}${app.reg_owner}${app.url_info_about}${app.description}${app.is_deleted}${new Date(app.create_at).toLocaleString()}${new Date(app.update_at).toLocaleString()}${new Date(app.deleted_at).toLocaleString()}
${info.ID}${info.Uuid}${info.HostName}${info.OsName}${info.OsVersion}${info.Family}${info.Architecture}${info.KernelVersion}${new Date(info.BootTime).toLocaleString()}${new Date(info.CreatedAt).toLocaleString()}${new Date(info.UpdatedAt).toLocaleString()}${info.id}${info.uuid}${info.host_name}${info.os_name}${info.os_version}${info.family}${info.architecture}${info.kernel_version}${new Date(info.boot_time).toLocaleString()}${new Date(info.created_at).toLocaleString()}${new Date(info.updated_at).toLocaleString()}
${data.operation_log.ID}${data.operation_log.AgentUUID}${data.operation_log.ProcedureID}${data.operation_log.InstructionUUID}${new Date(data.operation_log.ConductAt).toLocaleString()}${data.operation_log.ExitCode}${data.operation_log.Log}${data.operation_log.Command}
${log.ID}${log.AgentUUID}${log.ProcedureID}${log.InstructionUUID}${new Date(log.ConductAt).toLocaleString()}${log.ExitCode}${log.Log}${log.Command}
ID AgentUUID ProcedureIDInstructionUUIDMessageUUID ConductAt ExitCode LogID ProcedureID AgentUUIDInstructionUUIDMessageUUID CreatedAt
${log.ID} ${log.AgentUUID} ${log.ProcedureID}${log.InstructionUUID}${log.MessageUUID} ${new Date(log.ConductAt).toLocaleString()} ${log.ExitCode} ${log.Log}${job.id} ${job.procedureID} ${job.agentUUID}${job.instructionUUID}${job.messageUUID} ${new Date(job.createdAt).toLocaleString()}