This commit is contained in:
kingecg 2023-12-07 00:22:53 +08:00
parent 90014cec0c
commit 8107b7d567
13 changed files with 427 additions and 0 deletions

View File

@ -1,2 +1,10 @@
# gohttp
## 目标
实现一个类似nginx功能的http服务器
## 功能
- 支持静态文件
- Proxy
- 支持rewrite

57
admin/admin.go Normal file
View File

@ -0,0 +1,57 @@
package admin
import (
"net/http"
"strings"
)
type Route struct {
Method string
Path string
Handle http.HandlerFunc
}
func about(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("About Page"))
}
var AdminRoutes = []Route{
// Admin Routes
{"GET", "/about", about},
}
type PServeMux struct {
// routes map[string]map[string]http.HandlerFunc
*http.ServeMux
}
func (p *PServeMux) Use(route Route) {
method := strings.ToLower(route.Method)
p.ServeMux.HandleFunc("/"+method+route.Path, route.Handle)
// _, exist := p.routes[route.Path]
// if !exist {
// mroutes := make(map[string]http.HandlerFunc)
// p.routes[route.Path] = mroutes
// p.ServeMux.HandleFunc(route.Path, func(w http.ResponseWriter, r *http.Request) {
// p.routes[route.Path][r.Method](w, r)
// })
// }
// p.routes[route.Path][route.Method] = route.Handle
}
func (p *PServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
r.URL.Path = "/" + strings.ToLower(r.Method) + r.URL.Path
r.RequestURI = "/" + strings.ToLower(r.Method) + r.RequestURI
p.ServeMux.ServeHTTP(w, r)
}
var AdminServerMux *PServeMux
func init() {
AdminServerMux = &PServeMux{ServeMux: http.NewServeMux()}
// AdminServerMux.routes = make(map[string]map[string]http.HandlerFunc)
for _, route := range AdminRoutes {
AdminServerMux.Use(route)
}
}

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module git.pyer.club/kingecg/gohttpd
go 1.19
require git.pyer.club/kingecg/gologger v1.0.0 // indirect

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
git.pyer.club/kingecg/gologger v1.0.0 h1:H3oFIJ1p7mlAgJgJ/wiM+hxn34x7IxY4YiafY8iMfAk=
git.pyer.club/kingecg/gologger v1.0.0/go.mod h1:SNSl2jRHPzIpHSzdKOoVG798rtYMjPDPFyxUrEgivkY=

42
main.go Normal file
View File

@ -0,0 +1,42 @@
package main
import (
"net/http"
admin "git.pyer.club/kingecg/gohttpd/admin"
logger "git.pyer.club/kingecg/gologger"
)
func main() {
logger.Configure(logger.LoggersConfig{
Categories: map[string]logger.LogConfig{
"default": {
Level: "debug",
Appenders: []string{
"console",
},
},
"fat": {
Level: "debug",
Appenders: []string{
"console",
"file",
},
},
},
Appenders: map[string]logger.LogAppenderConfig{
"console": {
Type: "console",
},
"file": {
Type: "file",
Options: map[string]interface{}{
"file": "./log/fat.log",
},
},
},
})
defaultLogger := logger.GetLogger("default")
defaultLogger.Info("Listening...")
http.ListenAndServe(":8080", admin.AdminServerMux)
}

25
model/model.go Normal file
View File

@ -0,0 +1,25 @@
package model
type HttpPath struct {
Path string `json:"path"`
Root string `json:"root"`
Proxyto string `json:"proxyto"`
ProxyHeaders string `json:"proxyheaders"`
}
type HttpServerConfig struct {
ServerName string `json:"server"`
Port int `json:"port"`
Host string `json:"host"`
Paths []HttpPath
}
type GoHttpdConfig struct {
Admin HttpServerConfig `json:"admin"`
Servers []HttpServerConfig `json:"servers"`
}
var DefaultAdminConfig HttpServerConfig = HttpServerConfig{
ServerName: "admin",
Port: 8080,
}

View File

@ -0,0 +1,17 @@
# ---> Go
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/

View File

@ -0,0 +1,3 @@
# gologger
a logger used in go

View File

@ -0,0 +1,44 @@
package gologger
import (
"fmt"
)
const (
ErrorTemplate = "\033[1;31m%s\033[0m"
WarnTemplate = "\033[1;33m%s\033[0m"
InfoTemplate = "\033[1;32m%s\033[0m"
DebugTemplate = "\033[1;34m%s\033[0m"
TraceTemplate = "\033[1;35m%s\033[0m"
)
type ConsoleAppender struct {
}
func (c *ConsoleAppender) GetName() string {
return "console"
}
func (c *ConsoleAppender) Append(logEvent LogEvent) {
logMsg := format(logEvent)
switch logEvent.Level {
case Error:
fmt.Printf(ErrorTemplate, logMsg)
case Warn:
fmt.Printf(WarnTemplate, logMsg)
case Info:
fmt.Printf(InfoTemplate, logMsg)
case Debug:
fmt.Printf(DebugTemplate, logMsg)
case Trace:
fmt.Printf(TraceTemplate, logMsg)
}
}
func makeConsoleAppender(appenderConfig LogAppenderConfig) LoggerAppender {
var appender LoggerAppender = &ConsoleAppender{}
return appender
}
func init() {
RegistAppender("console", makeConsoleAppender)
}

View File

@ -0,0 +1,47 @@
package gologger
import (
"os"
"path/filepath"
)
type FileAppender struct {
filePath string
file *os.File
}
func (f *FileAppender) GetName() string {
return "FileAppender:" + f.filePath
}
func (f *FileAppender) Append(logEvent LogEvent) {
if f.file == nil || int(f.file.Fd()) == -1 {
dirName := filepath.Dir(f.filePath)
_, err := os.Stat(dirName)
if err != nil && os.IsNotExist(err) {
os.MkdirAll(dirName, 0755)
}
f.file, _ = os.OpenFile(f.filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
}
logMsg := format(logEvent)
f.file.WriteString(logMsg)
}
func makeFileAppender(appenderConfig LogAppenderConfig) LoggerAppender {
var logfile interface{}
var ok bool
logfile, ok = appenderConfig.Options["file"]
if !ok {
logfile = "default.log"
}
var ret LoggerAppender = &FileAppender{
filePath: logfile.(string),
}
return ret
}
func init() {
RegistAppender("file", makeFileAppender)
}

View File

@ -0,0 +1,23 @@
package gologger
import (
"fmt"
)
const logTemplate = "[%s] %s - %s\n"
func format(logEvent LogEvent) string {
data := logEvent.Ts.Format("2006-01-02 15:04:05")
msg := fmt.Sprint(logEvent.Data...)
ret := fmt.Sprintf(logTemplate, data, getLogLevelStr(logEvent.Level), msg)
return ret
}
func getLogLevelStr(level int) string {
for name, slevel := range logLevelMap {
if slevel == level {
return name
}
}
return "Unknown"
}

View File

@ -0,0 +1,151 @@
package gologger
import (
"strings"
"time"
)
const (
NoLog = iota
Error
Warn
Info
Debug
Trace
)
var logLevelMap map[string]int = map[string]int{
"off": NoLog,
"error": Error,
"warn": Warn,
"info": Info,
"debug": Debug,
"trace": Trace,
}
var loggerMap map[string]Logger = map[string]Logger{}
var appenderFactoryMap map[string]func(LogAppenderConfig) LoggerAppender = map[string]func(LogAppenderConfig) LoggerAppender{}
var appenders map[string]LoggerAppender = map[string]LoggerAppender{}
var loggerConfig LoggersConfig
type LogAppenderConfig struct {
Type string `json:"type"`
Options map[string]interface{} `json:"options"`
}
type LogConfig struct {
Level string `json:"level"`
Appenders []string `json:"appenders"`
}
type LoggersConfig struct {
Appenders map[string]LogAppenderConfig `json:"appenders"`
Categories map[string]LogConfig `json:"categories"`
}
type Logger struct {
category string
level int
appenders []LoggerAppender
}
type LogEvent struct {
Category string
Ts time.Time
Level int
Data []interface{}
}
type LoggerAppender interface {
GetName() string
Append(logEvent LogEvent)
}
var consoleAppender LoggerAppender = &ConsoleAppender{}
var defaultLogger = &Logger{
level: Error,
appenders: []LoggerAppender{consoleAppender},
}
func (l *Logger) log(Level int, msg []interface{}) {
if Level <= l.level {
now := time.Now()
logEvent := LogEvent{l.category, now, Level, msg}
for _, appender := range l.appenders {
appender.Append(logEvent)
}
// l.Appender.Append(logEvent)
// fmt.Println(now.Format("2006-01-02 15:04:05"), " ", l.Name, ": ", msg)
}
}
func (l *Logger) Error(msg ...interface{}) {
l.log(Error, msg)
}
func (l *Logger) Warn(msg ...interface{}) {
l.log(Warn, msg)
}
func (l *Logger) Info(msg ...interface{}) {
l.log(Info, msg)
}
func (l *Logger) Debug(msg ...interface{}) {
l.log(Debug, msg)
}
func (l *Logger) Trace(msg ...interface{}) {
l.log(Trace, msg)
}
func GetLogger(name string) Logger {
if logger, ok := loggerMap[name]; ok {
return logger
} else {
logConfig, ok := loggerConfig.Categories[name]
if ok {
return makeLogger(name, logConfig)
}
if name == "default" {
return *defaultLogger
}
ret := GetLogger("default")
ret.category = name
return ret
}
}
func makeLogger(name string, config LogConfig) Logger {
logger := &Logger{category: name}
levelstr := strings.ToLower(config.Level)
logger.level = logLevelMap[levelstr]
if config.Appenders == nil || len(config.Appenders) == 0 {
logger.appenders = []LoggerAppender{consoleAppender}
} else {
logger.appenders = make([]LoggerAppender, len(config.Appenders))
for i, appenderName := range config.Appenders {
logger.appenders[i] = appenders[appenderName]
}
}
loggerMap[name] = *logger
return *logger
}
func Configure(config LoggersConfig) {
loggerConfig = config
for name, appenderConfig := range loggerConfig.Appenders {
appenderFactory, ok := appenderFactoryMap[appenderConfig.Type]
if ok {
appenders[name] = appenderFactory(appenderConfig)
} else {
appenders[name] = &ConsoleAppender{}
}
}
for name, _ := range loggerConfig.Categories {
GetLogger(name)
}
}
func RegistAppender(typeName string, appenderCreatCb func(LogAppenderConfig) LoggerAppender) {
appenderFactoryMap[typeName] = appenderCreatCb
}

3
vendor/modules.txt vendored Normal file
View File

@ -0,0 +1,3 @@
# git.pyer.club/kingecg/gologger v1.0.0
## explicit; go 1.19
git.pyer.club/kingecg/gologger