add lua support

lua
dingjun 5 years ago
parent c39fc8c107
commit 350ec51345

@ -0,0 +1,53 @@
local http = require "http"
local json = require "json"
local mysql = require "mysql"
local redis = require "redis"
infolog(string.format("%s %s %s", request:GetIP(),request.Method,request.RequestURI))
-- response:Write(string.format("hello %s\n",request:GetIP()))
if request.URL.Path == "/api/ip" then
local resp = http.get("http://httpbin.org/ip")
local d = json.decode(resp.body)
print(d)
infolog(string.format("ip %s",d.origin))
local hdr = response:Header()
hdr:Set("content-type","application/json")
response:Write(resp.body)
return
end
if request.URL.Path == "/api/user" then
local c = mysql.new()
local ok, err = c:connect({host="127.0.0.1",user="root",password="112233",database="game"})
if not ok then
error(err)
return
end
local res, err = c:query("select * from `user` limit 3")
if err ~= nil then
error(err)
return
end
for k,v in pairs(res) do
print(k,v)
for k1,v1 in pairs(v) do
print(k1,v1)
end
end
local hdr = response:Header()
hdr:Set("content-type","application/json")
response:Write(json.encode(res))
c:close()
return
end
if request.URL.Path == "/api/user2" then
local c = redis.new({host="127.0.0.1"})
local keys = c:Do("keys", "wallet*"):Val()
for k, v in keys() do
response:Write(string.format("%s %s\n", k, v))
end
c:Close()
end

@ -0,0 +1,82 @@
package main
import (
"bufio"
"os"
"sync"
"github.com/fangdingjun/go-log"
lua "github.com/yuin/gopher-lua"
"github.com/yuin/gopher-lua/parse"
)
// from https://github.com/yuin/gophoer-lua
// CompileLua reads the passed lua file from disk and compiles it.
func CompileLua(filePath string) (*lua.FunctionProto, error) {
file, err := os.Open(filePath)
defer file.Close()
if err != nil {
return nil, err
}
reader := bufio.NewReader(file)
chunk, err := parse.Parse(reader, filePath)
if err != nil {
return nil, err
}
proto, err := lua.Compile(chunk, filePath)
if err != nil {
return nil, err
}
return proto, nil
}
// DoCompiledFile takes a FunctionProto, as returned by CompileLua, and runs it in the LState. It is equivalent
// to calling DoFile on the LState with the original source file.
func DoCompiledFile(L *lua.LState, proto *lua.FunctionProto) error {
lfunc := L.NewFunctionFromProto(proto)
L.Push(lfunc)
return L.PCall(0, lua.MultRet, nil)
}
type filecache struct {
filepath string
proto *lua.FunctionProto
lastMod int64
}
var cache = map[string]*filecache{}
var mu = new(sync.Mutex)
func runFile(vm *lua.LState, filepath string) error {
mu.Lock()
c, ok := cache[filepath]
if !ok {
c = &filecache{
filepath: filepath,
lastMod: 0,
}
cache[filepath] = c
}
fi, err := os.Stat(filepath)
if err != nil {
mu.Unlock()
return err
}
t := fi.ModTime().Unix()
if t > c.lastMod {
log.Debugf("file %s changed, reload", filepath)
proto, err := CompileLua(filepath)
if err != nil {
mu.Unlock()
return err
}
c.proto = proto
c.lastMod = t
}
mu.Unlock()
// log.Println(c.proto)
return DoCompiledFile(vm, c.proto)
}

@ -33,6 +33,10 @@ type vhost struct {
Docroot string `yaml:"docroot"`
Hostname string `yaml:"hostname"`
ProxyPass string `yaml:"proxypass"`
URLRules []struct {
Prefix string `yaml:"prefix"`
LuaFile string `yaml:"lua_file"`
} `yaml:"url_rules"`
}
func loadConfig(fn string) (*conf, error) {

@ -0,0 +1,29 @@
# vim: set ft=yaml:
# when provide certficate file, server will listen https and enable http2
listen:
-
addr: 0.0.0.0
port: 9001
certificates:
# virtual host support
vhost:
-
hostname: www.ratafee.nl
docroot: .
# proxypass: http://nginx:80/
url_rules:
- prefix: /api/
lua_file: api.lua
proxy:
http1-proxy: false
http2-proxy: true
# trust the follow domains as local virtual host
# when http2 proxy enabled
localdomains:
- localhost
- localdomain
- 127.0.0.1
- ratafee.nl
- 98.142.138.194

@ -20,6 +20,9 @@ vhost:
hostname: www.ratafee.nl
docroot: /srv/www
proxypass: http://nginx:80/
url_rules:
- prefix: /api/
lua_file: api.lua
proxy:
http1-proxy: false
http2-proxy: true

@ -3,13 +3,18 @@ module github.com/fangdingjun/gserver
go 1.13
require (
github.com/cjoudrey/gluahttp v0.0.0-20190104103309-101c19a37344
github.com/fangdingjun/go-log v0.0.0-20190821073628-ae332053d6dc
github.com/fangdingjun/gopher-redis v0.0.0-20190823083833-93d88f74dd35
github.com/fangdingjun/protolistener v0.0.0-20190821093313-6d5d2138f296
github.com/go-sql-driver/mysql v1.4.1 // indirect
github.com/go-yaml/yaml v2.1.0+incompatible
github.com/gorilla/handlers v1.4.2
github.com/gorilla/mux v1.7.3
github.com/kr/pretty v0.1.0 // indirect
github.com/junhsieh/goexamples v0.0.0-20190721045834-1c67ae74caa6 // indirect
github.com/tengattack/gluasql v0.0.0-20181229041402-2e5ed630c4cf
github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427
layeh.com/gopher-luar v1.0.7
)

@ -1,31 +1,49 @@
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cjoudrey/gluahttp v0.0.0-20190104103309-101c19a37344 h1:nTK6O2RY1nHC4jNEJd1nixVP7ygY3QE4CNxCX07dHKU=
github.com/cjoudrey/gluahttp v0.0.0-20190104103309-101c19a37344/go.mod h1:X97UjDTXp+7bayQSFZk2hPvCTmTZIicUjZQRtkwgAKY=
github.com/fangdingjun/go-log v0.0.0-20190821073628-ae332053d6dc h1:Tdk7VsmsFo3d0NqHTy3SRoRnkduOxwXgR65gQsq8kXY=
github.com/fangdingjun/go-log v0.0.0-20190821073628-ae332053d6dc/go.mod h1:oi7jbIScCbha6TbVzmrJP6igIHt+jcvvEgSJ7Ww1GkI=
github.com/fangdingjun/gopher-redis v0.0.0-20190823083833-93d88f74dd35 h1:ylhL3mOAVv+xPvF7ml4mPJkacGyc4hDAxBRl8/DGATk=
github.com/fangdingjun/gopher-redis v0.0.0-20190823083833-93d88f74dd35/go.mod h1:mJh0kXIkwwPbU3KnTswNRDtHUtA+xlFJRHnbxuFg33Y=
github.com/fangdingjun/protolistener v0.0.0-20190821093313-6d5d2138f296 h1:2c6agkdoPVSyvdJ0B+5DhOb1BQpso7a7zlBxXUnttmY=
github.com/fangdingjun/protolistener v0.0.0-20190821093313-6d5d2138f296/go.mod h1:RoT81rjdN8gQ1w/z7NiFkxV6VzkT4NZ43XIt0lu8tcc=
github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/pires/go-proxyproto v0.0.0-20190111085350-4d51b51e3bfc h1:lNOt1SMsgHXTdpuGw+RpnJtzUcCb/oRKZP65pBy9pr8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/junhsieh/goexamples v0.0.0-20190721045834-1c67ae74caa6 h1:oi85CfIzfVPMlTf6pteDMw0S3AjZ9b6Y0OaxfsLCU3M=
github.com/junhsieh/goexamples v0.0.0-20190721045834-1c67ae74caa6/go.mod h1:JNqB8Da6SnlJvmZusESDfgqUkJXO6+/a1by1etsVJ2M=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.9.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.6.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pires/go-proxyproto v0.0.0-20190111085350-4d51b51e3bfc/go.mod h1:6/gX3+E/IYGa0wMORlSMla999awQFdbaeQCHjSMKIzY=
github.com/tengattack/gluasql v0.0.0-20181229041402-2e5ed630c4cf h1:7zGSyMKHHwD0A8iJk0IlP8FhSIOZco4VyzemWYHP1Ck=
github.com/tengattack/gluasql v0.0.0-20181229041402-2e5ed630c4cf/go.mod h1:m4UsFo0sc87XS8WozZBD8HJPC2NKI/nB7w4N58HwemQ=
github.com/yuin/gopher-lua v0.0.0-20190206043414-8bfc7677f583/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
github.com/yuin/gopher-lua v0.0.0-20190514113301-1cd887cd7036/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a h1:Igim7XhdOpBnWPuYJ70XcNpq8q3BCACtVgNfoJxOV7g=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427 h1:RZkKxMR3jbQxdCEcglq3j7wY3PRJIopAwBlx1RE71X0=
layeh.com/gopher-json v0.0.0-20190114024228-97fed8db8427/go.mod h1:ivKkcY8Zxw5ba0jldhZCYYQfGdb2K6u9tbYK1AwMIBc=
layeh.com/gopher-luar v1.0.7 h1:53iv6CCkRs5wyofZ+qVXcyAYQOIG52s6pt4xkqZdq7k=
layeh.com/gopher-luar v1.0.7/go.mod h1:TPnIVCZ2RJBndm7ohXyaqfhzjlZ+OA2SZR/YwL8tECk=

@ -0,0 +1,17 @@
package main
import (
"github.com/fangdingjun/go-log"
)
func infoLog(msg string) {
log.Println(msg)
}
func errorLog(msg string) {
log.Errorln(msg)
}
func debugLog(msg string) {
log.Debugln(msg)
}

@ -0,0 +1,49 @@
package main
import (
"io/ioutil"
"net"
"net/http"
"github.com/fangdingjun/go-log"
luar "layeh.com/gopher-luar"
)
type luaHandler struct {
scriptFile string
}
func (l *luaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
vm := luaPool.Get()
defer luaPool.Put(vm)
vm.SetGlobal("request", luar.New(vm, &req{r}))
vm.SetGlobal("response", luar.New(vm, w))
if err := runFile(vm, l.scriptFile); err != nil {
log.Errorln(err)
http.Error(w, "server error", http.StatusInternalServerError)
}
}
type req struct {
*http.Request
}
func (r1 *req) GetBody() (string, error) {
d, err := ioutil.ReadAll(r1.Body)
return string(d), err
}
func (r1 *req) GetIP() string {
ip := r1.Header.Get("x-real-ip")
if ip != "" {
return ip
}
ip = r1.Header.Get("x-forwarded-for")
if ip != "" {
return ip
}
host, _, _ := net.SplitHostPort(r1.RemoteAddr)
return host
}

@ -0,0 +1,68 @@
package main
import (
"net/http"
"sync"
gluahttp "github.com/cjoudrey/gluahttp"
lua "github.com/yuin/gopher-lua"
luajson "layeh.com/gopher-json"
luar "layeh.com/gopher-luar"
mysql "github.com/tengattack/gluasql/mysql"
redis "github.com/fangdingjun/gopher-redis"
)
// from https://github.com/yuin/gophoer-lua
type lStatePool struct {
m sync.Mutex
saved []*lua.LState
}
func (pl *lStatePool) Get() *lua.LState {
pl.m.Lock()
defer pl.m.Unlock()
n := len(pl.saved)
if n == 0 {
return pl.New()
}
x := pl.saved[n-1]
pl.saved = pl.saved[0 : n-1]
return x
}
func (pl *lStatePool) New() *lua.LState {
L := lua.NewState()
luajson.Preload(L)
L.PreloadModule("http", gluahttp.NewHttpModule(&http.Client{}).Loader)
L.PreloadModule("mysql", mysql.Loader)
L.PreloadModule("redis", redis.Loader)
L.SetGlobal("infolog", luar.New(L, infoLog))
L.SetGlobal("errorlog", luar.New(L, errorLog))
L.SetGlobal("debuglog", luar.New(L, debugLog))
// setting the L up here.
// load scripts, set global variables, share channels, etc...
return L
}
func (pl *lStatePool) Put(L *lua.LState) {
pl.m.Lock()
defer pl.m.Unlock()
pl.saved = append(pl.saved, L)
}
func (pl *lStatePool) Shutdown() {
pl.m.Lock()
defer pl.m.Unlock()
for _, L := range pl.saved {
L.Close()
}
}
// Global LState pool
var luaPool = &lStatePool{
saved: make([]*lua.LState, 0, 4),
}

@ -24,12 +24,19 @@ func initServer(c *conf) error {
for _, vh := range c.Vhosts {
subroute := mux.Host(vh.Hostname)
for _, rule := range vh.URLRules {
subroute.PathPrefix(rule.Prefix).Handler(&luaHandler{rule.LuaFile})
}
subroute.PathPrefix("/").Handler(http.FileServer(http.Dir(vh.Docroot)))
}
mux.PathPrefix("/debug/").Handler(http.DefaultServeMux)
if len(c.Vhosts) > 0 {
rules := c.Vhosts[0].URLRules
for _, rule := range rules {
mux.PathPrefix(rule.Prefix).Handler(&luaHandler{rule.LuaFile})
}
mux.PathPrefix("/").Handler(http.FileServer(http.Dir(c.Vhosts[0].Docroot)))
} else {
mux.PathPrefix("/").Handler(http.FileServer(http.Dir("/var/www/html")))

Loading…
Cancel
Save