diff --git a/README.md b/README.md index 523e45a..089960e 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,10 @@ # gohttp +## 目标 + +实现一个类似nginx功能的http服务器 +## 功能 + +- 支持静态文件 +- Proxy +- 支持rewrite diff --git a/admin/admin.go b/admin/admin.go new file mode 100644 index 0000000..1b8b5c0 --- /dev/null +++ b/admin/admin.go @@ -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) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..776b137 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module git.pyer.club/kingecg/gohttpd + +go 1.19 + +require git.pyer.club/kingecg/gologger v1.0.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..71d2b28 --- /dev/null +++ b/go.sum @@ -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= diff --git a/main.go b/main.go new file mode 100644 index 0000000..91ffcb9 --- /dev/null +++ b/main.go @@ -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) +} diff --git a/model/model.go b/model/model.go new file mode 100644 index 0000000..e6e0864 --- /dev/null +++ b/model/model.go @@ -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, +} diff --git a/vendor/git.pyer.club/kingecg/gologger/.gitignore b/vendor/git.pyer.club/kingecg/gologger/.gitignore new file mode 100644 index 0000000..f4d432a --- /dev/null +++ b/vendor/git.pyer.club/kingecg/gologger/.gitignore @@ -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/ + diff --git a/vendor/git.pyer.club/kingecg/gologger/README.md b/vendor/git.pyer.club/kingecg/gologger/README.md new file mode 100644 index 0000000..6833230 --- /dev/null +++ b/vendor/git.pyer.club/kingecg/gologger/README.md @@ -0,0 +1,3 @@ +# gologger + +a logger used in go \ No newline at end of file diff --git a/vendor/git.pyer.club/kingecg/gologger/console.go b/vendor/git.pyer.club/kingecg/gologger/console.go new file mode 100644 index 0000000..e5bfb65 --- /dev/null +++ b/vendor/git.pyer.club/kingecg/gologger/console.go @@ -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) +} diff --git a/vendor/git.pyer.club/kingecg/gologger/file.go b/vendor/git.pyer.club/kingecg/gologger/file.go new file mode 100644 index 0000000..5d56227 --- /dev/null +++ b/vendor/git.pyer.club/kingecg/gologger/file.go @@ -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) +} diff --git a/vendor/git.pyer.club/kingecg/gologger/format.go b/vendor/git.pyer.club/kingecg/gologger/format.go new file mode 100644 index 0000000..48b3fa1 --- /dev/null +++ b/vendor/git.pyer.club/kingecg/gologger/format.go @@ -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" +} diff --git a/vendor/git.pyer.club/kingecg/gologger/main.go b/vendor/git.pyer.club/kingecg/gologger/main.go new file mode 100644 index 0000000..13c22cd --- /dev/null +++ b/vendor/git.pyer.club/kingecg/gologger/main.go @@ -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 +} diff --git a/vendor/modules.txt b/vendor/modules.txt new file mode 100644 index 0000000..46cdd8c --- /dev/null +++ b/vendor/modules.txt @@ -0,0 +1,3 @@ +# git.pyer.club/kingecg/gologger v1.0.0 +## explicit; go 1.19 +git.pyer.club/kingecg/gologger