Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Commit

Permalink
feat: update aliyun-serverless to Go 1.x runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
yin1999 committed Apr 2, 2022
1 parent 92c0787 commit b98c2f3
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 93 deletions.
11 changes: 9 additions & 2 deletions .github/workflows/Build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,15 @@ jobs:
go-version: ${{ env.GoVersion }}

- name: Download dependency
run: make dep
run: go mod download

- name: Build
run: |
make build
# spread the work across 2 processes
build1=$!
go build -tags aliyun
build2=$!
go build -tags tencent
wait $build1
wait $build2
11 changes: 9 additions & 2 deletions .github/workflows/Release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,18 @@ jobs:
go-version: ${{ env.GoVersion }}

- name: Download dependency
run: make dep
run: go mod download

- name: Build
run: |
make all
# spread the work across 2 processes
build1=$!
go run _script/build.go aliyun
build2=$!
go run _script/build.go tencent
wait $build1
wait $build2
- name: Create Release
if: github.event_name != 'release'
Expand Down
18 changes: 0 additions & 18 deletions Makefile

This file was deleted.

85 changes: 85 additions & 0 deletions _script/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package main

import (
"archive/zip"
"fmt"
"io"
"os"
"os/exec"
)

func main() {
var targets []string
if len(os.Args) == 1 {
targets = []string{"aliyun", "tencent"}
} else {
targets = os.Args[1:]
}
os.Setenv("GOOS", "linux")
os.Setenv("GOARCH", "amd64")
for _, target := range targets {
var out string
switch target {
case "aliyun":
out = "main"
case "tencent":
out = "bootstrap"
default:
panic("not supported platform")
}
cmd := exec.Command("go",
"build",
"-trimpath",
"-ldflags", "-s -w -buildid=",
"-tags", target,
"-o", out,
)
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Printf("%s\n", string(output))
panic(err)
}
err = zipFile(target+"-serverless.zip", out)
if err != nil {
fmt.Printf("%s\n", string(output))
panic(err)
}
os.Remove(out)
}
}

func zipFile(output, file string) (err error) {
var out *os.File
out, err = os.OpenFile(output, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
return
}
defer func() {
out.Close()
if err != nil {
os.Remove(output)
}
}()
w := zip.NewWriter(out)
var writer io.Writer
header := &zip.FileHeader{
Name: file,
Method: zip.Deflate,
}
header.SetMode(0755) // set executable permission
writer, err = w.CreateHeader(header)
if err != nil {
return
}
var in *os.File
in, err = os.Open(file)
if err != nil {
return
}
defer in.Close()
if _, err = io.Copy(writer, in); err != nil {
return
}
err = w.Close()
return
}
74 changes: 42 additions & 32 deletions aliyun.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
package main

import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strings"
)

type timerTrigger struct {
Expand All @@ -16,45 +17,54 @@ type timerTrigger struct {
}

const (
fcStatus = "X-Fc-Status"
fcStatus = "X-Fc-Status"
fcRequestId = "X-Fc-Request-Id"
apiVersion = "2020-11-11"
contentType = "text/plain"
)

func regist() (handler, error) {
port := os.Getenv("FC_SERVER_PORT")
if port == "" {
port = "9000"
}
address := os.Getenv("FC_RUNTIME_API")
endpoint := fmt.Sprintf("http://%s/%s/runtime/invocation/", address, apiVersion)
return &aliyun{
port: port,
endpoint: endpoint,
client: http.Client{},
}, nil
}

type aliyun struct {
port string
endpoint string
ua string
client http.Client
}

func (a aliyun) Next() (body io.ReadCloser, reqID string, err error) {
var resp *http.Response
resp, err = http.Get(a.endpoint + "next")
if err == nil {
body = resp.Body
reqID = resp.Header.Get(fcRequestId)
}
return
}

func (a aliyun) ListenAndServe(punch func(payload string) error) error {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
requestId := r.Header.Get("X-Fc-Request-Id")
fmt.Printf("FC Invoke Start RequestId: %s\n", requestId)
defer fmt.Printf("FC Invoke End RequestId: %s\n", requestId)

t := &timerTrigger{}
err := json.NewDecoder(r.Body).Decode(t)

if err != nil {
Fatal.Log("error payload format\n")
w.Header().Set(fcStatus, "404")
w.Write([]byte("error payload format"))
return
}
err = punch(t.Payload)
if err != nil {
w.Header().Set(fcStatus, "404")
fmt.Fprintf(w, "Punch Failed: %s", err.Error())
} else {
w.Write([]byte("success"))
}
})
return http.ListenAndServe(":"+a.port, nil)
func (a aliyun) ReportSuccess(id string) {
res, err := http.DefaultClient.Post(a.endpoint+id+"/response", contentType, http.NoBody)
if err == nil {
res.Body.Close()
} else {
Error.Log(err.Error() + "\n")
}
}

func (a aliyun) ReportError(msg string, id string) {
res, err := http.Post(a.endpoint+id+"/error",
contentType,
strings.NewReader(msg),
)
if err == nil {
res.Body.Close()
} else {
Error.Log(err.Error() + "\n")
}
}
35 changes: 31 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package main

import (
"context"
"encoding/json"
"errors"
"io"
"os"
"strings"
"time"
Expand All @@ -11,17 +13,17 @@ import (
)

type handler interface {
ListenAndServe(punch func(payload string) error) error
Next() (body io.ReadCloser, reqID string, err error)
ReportError(msg string, id string)
ReportSuccess(id string)
}

func main() {
h, err := regist()
if err != nil {
os.Exit(1)
}
if err = h.ListenAndServe(punch); err != nil {
os.Exit(2)
}
startServe(h)
}

func init() {
Expand All @@ -30,6 +32,31 @@ func init() {
}
}

func startServe(handler handler) {
for {
body, id, err := handler.Next()
if err != nil {
Error.Log("get trigger payload failed, err: %s\n", err.Error())
continue
}
t := &timerTrigger{}
err = json.NewDecoder(body).Decode(t)
body.Close() // close body
if err != nil {
msg := "parse request body failed, err: " + err.Error()
Error.Log(msg + "\n")
handler.ReportError(msg, id)
continue
}
err = punch(t.Payload)
if err != nil {
handler.ReportError(err.Error(), id)
} else {
handler.ReportSuccess(id)
}
}
}

func punch(payload string) error {
account := strings.Fields(payload)
if len(account) < 2 {
Expand Down
59 changes: 24 additions & 35 deletions tencentCloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
package main

import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strings"
Expand All @@ -14,19 +15,19 @@ const contentType = "text/plain"
func regist() (handler, error) {
host := os.Getenv("SCF_RUNTIME_API")
port := os.Getenv("SCF_RUNTIME_API_PORT")
reportAPI := "http://" + host + ":" + port
res, err := http.Post(reportAPI+"/runtime/init/ready", contentType, http.NoBody)
endpoint := fmt.Sprintf("http://%s:%s/", host, port)
res, err := http.Post(endpoint+"runtime/init/ready", contentType, http.NoBody)
if err != nil {
return nil, err
}
res.Body.Close()
return &tencent{
reportAPI: reportAPI,
endpoint: endpoint,
}, err
}

type tencent struct {
reportAPI string
endpoint string
}

type timerTrigger struct {
Expand All @@ -35,39 +36,27 @@ type timerTrigger struct {
Payload string `json:"Message"`
}

func (h tencent) ListenAndServe(punch func(payload string) error) error {
for {
res, err := http.Get(h.reportAPI + "/runtime/invocation/next")
if err != nil {
Error.Log("get trigger payload failed, err: %s\n", err.Error())
h.reportError("get payload failed, err: " + err.Error() + "\n")
}
requestId := res.Header.Get("Request_id")
dec := json.NewDecoder(res.Body)
t := &timerTrigger{}
err = dec.Decode(t)
res.Body.Close() // close body
if err != nil {
msg := "parse request body failed, err: " + err.Error()
Error.Log(msg + "\n")
h.reportError(msg)
}
err = punch(t.Payload)
if err != nil {
h.reportError(err.Error() + "\n")
} else {
res, err := http.DefaultClient.Post(h.reportAPI+"/runtime/invocation/response", contentType, strings.NewReader(requestId))
if err == nil {
res.Body.Close()
} else {
Fatal.Log(err.Error() + "\n")
}
}
func (h tencent) Next() (body io.ReadCloser, id string, err error) {
var resp *http.Response
resp, err = http.Get(h.endpoint + "runtime/invocation/next")
if err == nil {
body = resp.Body
id = resp.Header.Get("Request_id")
}
return
}

func (h tencent) ReportSuccess(id string) {
res, err := http.DefaultClient.Post(h.endpoint+"runtime/invocation/response", contentType, strings.NewReader(id))
if err == nil {
res.Body.Close()
} else {
Fatal.Log(err.Error() + "\n")
}
}

func (h tencent) reportError(msg string) {
res, err := http.DefaultClient.Post(h.reportAPI+"/runtime/invocation/error",
func (h tencent) ReportError(msg string, _ string) {
res, err := http.DefaultClient.Post(h.endpoint+"runtime/invocation/error",
contentType,
strings.NewReader(msg),
)
Expand Down

0 comments on commit b98c2f3

Please sign in to comment.