Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
2
2401-0022-lte-fire-alarm
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
이병복
2401-0022-lte-fire-alarm
Commits
1a0d1a7f
Commit
1a0d1a7f
authored
Jun 27, 2024
by
이병복
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
프로그램추가
parent
6260df6f
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
535 additions
and
0 deletions
+535
-0
config.json
cmd/app-lte-alarm/config.json
+9
-0
main.go
cmd/app-lte-alarm/main.go
+229
-0
index.html
cmd/index.html
+159
-0
main.go
cmd/main.go
+138
-0
No files found.
cmd/app-lte-alarm/config.json
0 → 100644
View file @
1a0d1a7f
{
"serverAddress"
:
"localhost:8080"
,
"retryLimit"
:
5
,
"retryDelay"
:
2000
,
"logFilePath"
:
"app.log"
,
"maxLogSize"
:
10485760
,
"apiEndpoint"
:
"http://example.com/api/logs"
}
cmd/app-lte-alarm/main.go
0 → 100644
View file @
1a0d1a7f
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
])
}
cmd/index.html
0 → 100644
View file @
1a0d1a7f
<!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>
cmd/main.go
0 → 100644
View file @
1a0d1a7f
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"
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment