Add API to register server (#472)
This commit is contained in:
parent
3d6edd602c
commit
f4b7483807
8
.dockerignore
Normal file
8
.dockerignore
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
docker-compose.yml
|
||||||
|
Dockerfile
|
||||||
|
Dockerfile.dev
|
||||||
|
|
||||||
|
|
||||||
|
data/*
|
63
Dockerfile.dev
Normal file
63
Dockerfile.dev
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# Use build arguments for Go version and architecture
|
||||||
|
ARG GO_VERSION=1.22
|
||||||
|
ARG BUILDARCH=amd64
|
||||||
|
|
||||||
|
# Stage 1: Builder Stage
|
||||||
|
# FROM golang:${GO_VERSION}-alpine AS builder
|
||||||
|
FROM crazymax/xgo:${GO_VERSION} AS builder
|
||||||
|
|
||||||
|
# Set up working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Step 1: Copy the source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# use --mount=type=cache,target=/go/pkg/mod to cache the go mod
|
||||||
|
# Step 2: Download dependencies
|
||||||
|
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||||
|
go mod tidy && go mod download
|
||||||
|
|
||||||
|
# Step 3: Build the Go application with CGO enabled and specified ldflags
|
||||||
|
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||||
|
CGO_ENABLED=1 GOOS=linux go build -a \
|
||||||
|
-ldflags "-s -w --extldflags '-static -fpic'" \
|
||||||
|
-installsuffix cgo -o dashboard cmd/dashboard/main.go
|
||||||
|
|
||||||
|
|
||||||
|
# Stage 2: Create the final image
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
ARG COUNTRY
|
||||||
|
# Install required tools without caching index to minimize image size
|
||||||
|
RUN if [ "$COUNTRY" = "CN" ] ; then \
|
||||||
|
echo "It is in China, updating the repositories"; \
|
||||||
|
sed -i 's#https\?://dl-cdn.alpinelinux.org/alpine#https://mirrors.tuna.tsinghua.edu.cn/alpine#g' /etc/apk/repositories; \
|
||||||
|
fi && \
|
||||||
|
apk update && apk add --no-cache tzdata && \
|
||||||
|
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
|
||||||
|
echo 'Asia/Shanghai' >/etc/timezone && \
|
||||||
|
rm -rf /var/cache/apk/* && \
|
||||||
|
mkdir -p /dashboard/data
|
||||||
|
|
||||||
|
|
||||||
|
# Copy the entrypoint script and ensure it is executable
|
||||||
|
COPY ./script/entrypoint.sh /entrypoint.sh
|
||||||
|
|
||||||
|
# Set up the entrypoint script
|
||||||
|
RUN chmod +x /entrypoint.sh
|
||||||
|
|
||||||
|
WORKDIR /dashboard
|
||||||
|
|
||||||
|
# Copy the statically linked binary from the builder stage
|
||||||
|
COPY --from=builder /app/dashboard ./app
|
||||||
|
# Copy the configuration file and the resource directory
|
||||||
|
COPY ./script/config.yaml ./data/config.yaml
|
||||||
|
COPY ./resource ./resource
|
||||||
|
|
||||||
|
|
||||||
|
# Set up volume and expose ports
|
||||||
|
VOLUME ["/dashboard/data"]
|
||||||
|
EXPOSE 80 5555 443
|
||||||
|
|
||||||
|
# Define the entrypoint
|
||||||
|
ENTRYPOINT ["/entrypoint.sh"]
|
@ -28,6 +28,7 @@ func (v *apiV1) serve() {
|
|||||||
}))
|
}))
|
||||||
r.GET("/server/list", v.serverList)
|
r.GET("/server/list", v.serverList)
|
||||||
r.GET("/server/details", v.serverDetails)
|
r.GET("/server/details", v.serverDetails)
|
||||||
|
r.POST("/server/register", v.RegisterServer)
|
||||||
// 不强制认证的 API
|
// 不强制认证的 API
|
||||||
mr := v.r.Group("monitor")
|
mr := v.r.Group("monitor")
|
||||||
mr.Use(mygin.Authorize(mygin.AuthorizeOption{
|
mr.Use(mygin.Authorize(mygin.AuthorizeOption{
|
||||||
@ -83,6 +84,45 @@ func (v *apiV1) serverDetails(c *gin.Context) {
|
|||||||
c.JSON(200, singleton.ServerAPI.GetAllStatus())
|
c.JSON(200, singleton.ServerAPI.GetAllStatus())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterServer adds a server and responds with the full ServerRegisterResponse
|
||||||
|
// header: Authorization: Token
|
||||||
|
// body: RegisterServer
|
||||||
|
// response: ServerRegisterResponse or Secret string
|
||||||
|
func (v *apiV1) RegisterServer(c *gin.Context) {
|
||||||
|
var rs singleton.RegisterServer
|
||||||
|
// Attempt to bind JSON to RegisterServer struct
|
||||||
|
if err := c.ShouldBindJSON(&rs); err != nil {
|
||||||
|
c.JSON(400, singleton.ServerRegisterResponse{
|
||||||
|
CommonResponse: singleton.CommonResponse{
|
||||||
|
Code: 400,
|
||||||
|
Message: "Parse JSON failed",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Check if simple mode is requested
|
||||||
|
simple := c.Query("simple") == "true" || c.Query("simple") == "1"
|
||||||
|
// Set defaults if fields are empty
|
||||||
|
if rs.Name == "" {
|
||||||
|
rs.Name = c.ClientIP()
|
||||||
|
}
|
||||||
|
if rs.Tag == "" {
|
||||||
|
rs.Tag = "AutoRegister"
|
||||||
|
}
|
||||||
|
if rs.HideForGuest == "" {
|
||||||
|
rs.HideForGuest = "on"
|
||||||
|
}
|
||||||
|
// Call the Register function and get the response
|
||||||
|
response := singleton.ServerAPI.Register(&rs)
|
||||||
|
// Respond with Secret only if in simple mode, otherwise full response
|
||||||
|
if simple {
|
||||||
|
c.JSON(response.Code, response.Secret)
|
||||||
|
} else {
|
||||||
|
c.JSON(response.Code, response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func (v *apiV1) monitorHistoriesById(c *gin.Context) {
|
func (v *apiV1) monitorHistoriesById(c *gin.Context) {
|
||||||
idStr := c.Param("id")
|
idStr := c.Param("id")
|
||||||
id, err := strconv.ParseUint(idStr, 10, 64)
|
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||||
|
17
docker-compose.yml
Normal file
17
docker-compose.yml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
services:
|
||||||
|
app:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
args:
|
||||||
|
COUNTRY: CN
|
||||||
|
image: nezha:dev
|
||||||
|
container_name: nezha-dev
|
||||||
|
ports:
|
||||||
|
- ${NEZHA_PORT:-80}:18080
|
||||||
|
- 5555:5555
|
||||||
|
volumes:
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
- ./data:/dashboard/data
|
||||||
|
# - ./resource:/dashboard/resource
|
@ -25,6 +25,19 @@ type CommonResponse struct {
|
|||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RegisterServer struct {
|
||||||
|
Name string
|
||||||
|
Tag string
|
||||||
|
Note string
|
||||||
|
HideForGuest string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerRegisterResponse struct {
|
||||||
|
CommonResponse
|
||||||
|
Secret string `json:"secret"`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
type CommonServerInfo struct {
|
type CommonServerInfo struct {
|
||||||
ID uint64 `json:"id"`
|
ID uint64 `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@ -227,6 +240,55 @@ func (s *ServerAPIService) GetAllList() *ServerInfoResponse {
|
|||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
func (s *ServerAPIService) Register(rs *RegisterServer) *ServerRegisterResponse {
|
||||||
|
var serverInfo model.Server
|
||||||
|
var err error
|
||||||
|
// Populate serverInfo fields
|
||||||
|
serverInfo.Name = rs.Name
|
||||||
|
serverInfo.Tag = rs.Tag
|
||||||
|
serverInfo.Note = rs.Note
|
||||||
|
serverInfo.HideForGuest = rs.HideForGuest == "on"
|
||||||
|
// Generate a random secret
|
||||||
|
serverInfo.Secret, err = utils.GenerateRandomString(18)
|
||||||
|
if err != nil {
|
||||||
|
return &ServerRegisterResponse{
|
||||||
|
CommonResponse: CommonResponse{
|
||||||
|
Code: 500,
|
||||||
|
Message: "Generate secret failed: " + err.Error(),
|
||||||
|
},
|
||||||
|
Secret: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Attempt to save serverInfo in the database
|
||||||
|
err = DB.Create(&serverInfo).Error
|
||||||
|
if err != nil {
|
||||||
|
return &ServerRegisterResponse{
|
||||||
|
CommonResponse: CommonResponse{
|
||||||
|
Code: 500,
|
||||||
|
Message: "Database error: " + err.Error(),
|
||||||
|
},
|
||||||
|
Secret: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
serverInfo.Host = &model.Host{}
|
||||||
|
serverInfo.State = &model.HostState{}
|
||||||
|
serverInfo.TaskCloseLock = new(sync.Mutex)
|
||||||
|
ServerLock.Lock()
|
||||||
|
SecretToID[serverInfo.Secret] = serverInfo.ID
|
||||||
|
ServerList[serverInfo.ID] = &serverInfo
|
||||||
|
ServerTagToIDList[serverInfo.Tag] = append(ServerTagToIDList[serverInfo.Tag], serverInfo.ID)
|
||||||
|
ServerLock.Unlock()
|
||||||
|
ReSortServer()
|
||||||
|
// Successful response
|
||||||
|
return &ServerRegisterResponse{
|
||||||
|
CommonResponse: CommonResponse{
|
||||||
|
Code: 200,
|
||||||
|
Message: "Server created successfully",
|
||||||
|
},
|
||||||
|
Secret: serverInfo.Secret,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *MonitorAPIService) GetMonitorHistories(query map[string]any) *MonitorInfoResponse {
|
func (m *MonitorAPIService) GetMonitorHistories(query map[string]any) *MonitorInfoResponse {
|
||||||
var (
|
var (
|
||||||
|
Loading…
Reference in New Issue
Block a user