Commit 1a0d1a7f by 이병복

프로그램추가

parent 6260df6f
{
"serverAddress": "localhost:8080",
"retryLimit": 5,
"retryDelay": 2000,
"logFilePath": "app.log",
"maxLogSize": 10485760,
"apiEndpoint": "http://example.com/api/logs"
}
package main
import (
"bytes"
"encoding/binary"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"os"
"os/exec"
"time"
"golang.org/x/text/encoding/korean"
)
// Config 구조체 정의
type Config struct {
ServerAddress string `json:"serverAddress"`
RetryLimit int `json:"retryLimit"`
RetryDelay int `json:"retryDelay"` // milliseconds
LogFilePath string `json:"logFilePath"`
MaxLogSize int64 `json:"maxLogSize"` // bytes
ApiEndpoint string `json:"apiEndpoint"`
}
// Packet 구조체 정의
type Packet struct {
LogSize byte
LogType byte
LogDatetime [6]byte
LogOn byte
LogAddress [7]byte
LogArea [24]byte
LogDevice [24]byte
}
type ParsedData struct {
LogSize byte `json:"logSize"`
LogType byte `json:"logType"`
LogDatetime string `json:"logDatetime"`
LogOn byte `json:"logOn"`
LogAddress string `json:"logAddress"`
LogArea string `json:"logArea"`
LogDevice string `json:"logDevice"`
}
const readTimeout = 1 * time.Minute // 응답 타임아웃 설정 (1분)
func main() {
// 설정 파일 읽기
config, err := loadConfig("config.json")
if err != nil {
log.Fatalf("Failed to load config: %v", err)
}
// 로그 파일 설정
logFile, err := os.OpenFile(config.LogFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatalf("Failed to open log file: %v", err)
}
defer logFile.Close()
log.SetOutput(io.MultiWriter(os.Stdout, logFile))
var conn net.Conn
for {
// 재시도 로직
for attempts := 0; attempts < config.RetryLimit; attempts++ {
conn, err = net.Dial("tcp", config.ServerAddress)
if err == nil {
log.Println("Connected to server")
break
}
log.Printf("Failed to connect to server (attempt %d/%d): %v", attempts+1, config.RetryLimit, err)
time.Sleep(time.Duration(config.RetryDelay) * time.Millisecond)
}
if err != nil {
log.Printf("Could not connect to server after %d attempts: %v", config.RetryLimit, err)
rebootSystem()
return
}
// 서버와 지속적인 연결 유지
for {
conn.SetReadDeadline(time.Now().Add(readTimeout))
packet := &Packet{}
err = binary.Read(conn, binary.BigEndian, packet)
if err != nil {
log.Printf("Read error: %v", err)
conn.Close()
break
}
// 각 필드 파싱 및 출력
parsedData := ParsedData{
LogSize: packet.LogSize,
LogType: packet.LogType,
LogDatetime: parseDatetime(packet.LogDatetime[:]),
LogOn: packet.LogOn,
LogAddress: string(bytes.Trim(packet.LogAddress[:], "\x00")),
LogArea: decodeEUC_KR(packet.LogArea[:]),
LogDevice: decodeEUC_KR(packet.LogDevice[:]),
}
log.Printf("Parsed Data: %+v\n", parsedData)
// 데이터 전송
err = sendToApi(config.ApiEndpoint, parsedData)
if err != nil {
log.Printf("Failed to send data to API: %v", err)
}
// 로그 파일 크기 체크 및 리셋
if err := checkLogSizeAndReset(config.LogFilePath, config.MaxLogSize); err != nil {
log.Fatalf("Failed to check log size: %v", err)
}
}
}
}
// 설정 파일을 읽어오는 함수
func loadConfig(filename string) (*Config, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
var config Config
err = json.Unmarshal(data, &config)
if err != nil {
return nil, err
}
return &config, nil
}
// EUC-KR 인코딩을 UTF-8로 디코딩하는 함수
func decodeEUC_KR(data []byte) string {
dec := korean.EUCKR.NewDecoder()
decoded, err := dec.Bytes(data)
if err != nil {
log.Fatalf("Failed to decode EUC-KR: %v", err)
}
return string(decoded)
}
// 시스템을 재부팅하는 함수
func rebootSystem() {
log.Println("Rebooting the system...")
cmd := exec.Command("reboot")
err := cmd.Run()
if err != nil {
log.Fatalf("Failed to reboot the system: %v", err)
}
}
// 로그 파일 크기 체크 및 리셋하는 함수
func checkLogSizeAndReset(logFilePath string, maxSize int64) error {
fileInfo, err := os.Stat(logFilePath)
if err != nil {
return err
}
if fileInfo.Size() >= maxSize {
log.Println("Log file size exceeded, resetting log file")
return resetLogFile(logFilePath)
}
return nil
}
// 로그 파일을 리셋하는 함수
func resetLogFile(logFilePath string) error {
// 기존 파일 닫기
logFile, err := os.OpenFile(logFilePath, os.O_TRUNC|os.O_WRONLY, 0644)
if err != nil {
return err
}
logFile.Close()
// 새로운 로그 파일 열기
logFile, err = os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
log.SetOutput(io.MultiWriter(os.Stdout, logFile))
return nil
}
// 데이터를 REST API로 전송하는 함수
func sendToApi(apiEndpoint string, data ParsedData) error {
jsonData, err := json.Marshal(data)
if err != nil {
return err
}
req, err := http.NewRequest("POST", apiEndpoint, bytes.NewBuffer(jsonData))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("API request failed with status: %s", resp.Status)
}
return nil
}
// 로그 발생 시각을 문자열로 변환하는 함수
func parseDatetime(data []byte) string {
return fmt.Sprintf("%02x-%02x-%02x %02x:%02x:%02x", data[0], data[1], data[2], data[3], data[4], data[5])
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Edit Configuration</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
}
label {
display: block;
margin-bottom: 5px;
}
input, button {
margin-bottom: 10px;
padding: 5px;
width: 300px;
}
button {
cursor: pointer;
}
#status {
margin-top: 10px;
}
</style>
</head>
<body>
<div id="loginPage">
<h1>Login</h1>
<label for="username">Username:</label>
<input type="text" id="username" value="">
<br>
<label for="password">Password:</label>
<input type="password" id="password" value="">
<br>
<button onclick="login()">Login</button>
<div id="loginStatus"></div>
</div>
<div id="editPage" style="display: none;">
<h1>Edit Configuration</h1>
<label for="serverAddress">Server Address:</label>
<input type="text" id="serverAddress" value="">
<br>
<label for="retryLimit">Retry Limit:</label>
<input type="number" id="retryLimit" value="">
<br>
<label for="retryDelay">Retry Delay (ms):</label>
<input type="number" id="retryDelay" value="">
<br>
<label for="logFilePath">Log File Path:</label>
<input type="text" id="logFilePath" value="">
<br>
<label for="maxLogSize">Max Log Size (bytes):</label>
<input type="number" id="maxLogSize" value="">
<br>
<label for="apiEndpoint">API Endpoint:</label>
<input type="text" id="apiEndpoint" value="">
<br>
<button onclick="saveConfig()">Save Configuration</button>
<div id="status"></div>
<br>
<button onclick="logout()">Logout</button>
</div>
<script>
let loggedIn = false;
function showLoginPage() {
document.getElementById('loginPage').style.display = 'block';
document.getElementById('editPage').style.display = 'none';
}
function showEditPage() {
document.getElementById('loginPage').style.display = 'none';
document.getElementById('editPage').style.display = 'block';
}
function login() {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
// 실제로는 서버에서 로그인을 처리해야 합니다 (여기서는 단순 예시로 처리)
if (username === 'admin' && password === 'password') {
loggedIn = true;
showEditPage();
fetchConfig();
} else {
document.getElementById('loginStatus').textContent = 'Invalid username or password';
}
}
function logout() {
loggedIn = false;
showLoginPage();
}
// 초기 설정 값을 입력 폼에 설정하는 함수
function populateFields(config) {
document.getElementById('serverAddress').value = config.serverAddress;
document.getElementById('retryLimit').value = config.retryLimit;
document.getElementById('retryDelay').value = config.retryDelay;
document.getElementById('logFilePath').value = config.logFilePath;
document.getElementById('maxLogSize').value = config.maxLogSize;
document.getElementById('apiEndpoint').value = config.apiEndpoint;
}
// 서버에서 현재 설정을 가져오는 함수
function fetchConfig() {
fetch('/config').then(response => response.json())
.then(config => {
populateFields(config);
})
.catch(error => {
console.error('Error fetching configuration:', error);
});
}
// 설정을 서버에 저장하는 함수
function saveConfig() {
var newConfig = {
serverAddress: document.getElementById('serverAddress').value,
retryLimit: parseInt(document.getElementById('retryLimit').value),
retryDelay: parseInt(document.getElementById('retryDelay').value),
logFilePath: document.getElementById('logFilePath').value,
maxLogSize: parseInt(document.getElementById('maxLogSize').value),
apiEndpoint: document.getElementById('apiEndpoint').value
};
fetch('/save', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newConfig),
})
.then(response => {
if (response.ok) {
document.getElementById('status').textContent = 'Configuration updated successfully';
} else {
document.getElementById('status').textContent = 'Failed to update configuration';
}
})
.catch(error => {
console.error('Error saving configuration:', error);
document.getElementById('status').textContent = 'Error saving configuration';
});
}
// 페이지 로드 시 로그인 페이지 보여주기
document.addEventListener('DOMContentLoaded', () => {
showLoginPage();
});
</script>
</body>
</html>
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"time"
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
)
// Config 구조체 정의
type Config struct {
ServerAddress string `json:"serverAddress"`
RetryLimit int `json:"retryLimit"`
RetryDelay int `json:"retryDelay"`
LogFilePath string `json:"logFilePath"`
MaxLogSize int64 `json:"maxLogSize"`
ApiEndpoint string `json:"apiEndpoint"`
}
var config Config
// 세션 저장소
var store = sessions.NewCookieStore([]byte("your-secret-key"))
func main() {
// 초기 설정 파일 읽기
configJSON := `
{
"serverAddress": "localhost:8080",
"retryLimit": 5,
"retryDelay": 2000,
"logFilePath": "app.log",
"maxLogSize": 10485760,
"apiEndpoint": "http://example.com/api/logs"
}`
err := json.Unmarshal([]byte(configJSON), &config)
if err != nil {
log.Fatalf("Failed to unmarshal config JSON: %v", err)
}
r := mux.NewRouter()
// 정적 파일 서빙
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("."))))
// 로그인 페이지
r.HandleFunc("/", serveLogin).Methods("GET")
r.HandleFunc("/login", loginHandler).Methods("POST")
// 보호된 페이지
editSubrouter := r.PathPrefix("/edit").Subrouter()
editSubrouter.HandleFunc("/", serveEdit).Methods("GET")
editSubrouter.HandleFunc("/config", getConfig).Methods("GET")
editSubrouter.HandleFunc("/save", saveConfig).Methods("POST")
editSubrouter.HandleFunc("/logout", logoutHandler).Methods("GET")
fmt.Println("Server listening on localhost:8000...")
log.Fatal(http.ListenAndServe(":8000", r))
}
// 로그인 페이지 서빙
func serveLogin(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, "index.html")
}
// 로그인 처리
func loginHandler(w http.ResponseWriter, r *http.Request) {
username := r.FormValue("username")
password := r.FormValue("password")
// 실제로는 여기에서 데이터베이스나 다른 인증 방식을 사용하여 검증해야 합니다.
if username == "admin" && password == "password" {
session, _ := store.Get(r, "session-name")
session.Values["authenticated"] = true
session.Save(r, w)
http.Redirect(w, r, "/edit", http.StatusSeeOther)
} else {
http.Error(w, "Invalid username or password", http.StatusUnauthorized)
}
}
// 로그아웃 처리
func logoutHandler(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "session-name")
session.Values["authenticated"] = false
session.Save(r, w)
http.Redirect(w, r, "/", http.StatusSeeOther)
}
// 보호된 페이지 서빙
func serveEdit(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "session-name")
val := session.Values["authenticated"]
if val == nil || !val.(bool) {
http.Redirect(w, r, "/", http.StatusSeeOther)
return
}
http.ServeFile(w, r, "index.html")
}
// 현재 설정을 제공하는 핸들러
func getConfig(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(config)
}
// 설정을 업데이트하는 핸들러
func saveConfig(w http.ResponseWriter, r *http.Request) {
session, _ := store.Get(r, "session-name")
val := session.Values["authenticated"]
if val == nil || !val.(bool) {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
var newConfig Config
err := json.NewDecoder(r.Body).Decode(&newConfig)
if err != nil {
http.Error(w, "Failed to decode JSON", http.StatusBadRequest)
return
}
config = newConfig
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Configuration updated successfully")
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment