text:
<repo_name>ChenHanZhang/microservices-in-golang<file_sep>/README.md
# microservices-in-golang

## 如何运行

0. 构建容器
```shell script
docker-compose build --no-cache
```
注意，目前仍无法使用 `docker-compose run or up`来运行服务，需要手动启用每个服务。

```shell script
docker-compose run <service-name>
```

1. 启动 mongoDB(如果不看日志可以略, vessel-service会启动这个服务)
2. 启动 postgres(如果不看日志可以略, user-service会启动这个服务)
3. 启动 vessel-service
4. 启动 user-service && 启动 user-cli(如果未获取token的话)
5. 启动 consignment-service
6. 修改 `consignment-cli/Dockefile`的token && 启动 consignment-cli

- 可选:
1. 启动 `email-service`
2. 启动 API 网关
```shell script
docker run -p 8080:8080 \
             -e MICRO_REGISTRY=mdns \
             microhq/micro api \
             --handler=rpc \
             --address=:8080 \
             --namespace=shippy
```

## TODO

1. 如何用 `docker-compose` 来编排容器
2. 容器会重复启动吗
3. 如何设计错误处理，特别是调用链非常长的情况下
4. ctx 是如何传递的(在token为空情况下这个bug竟然一路传递到了user-service上)
<file_sep>/email-service/Dockerfile
FROM golang:1.13 as builder

# 将工作目录设置为当前微服务在gopath中的完整路径
WORKDIR /go/src/github.com/ChenHanZhang/microservices-in-golang/email-service

# 将代码复制到工作目录中
COPY . .

ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.cn

RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .

FROM alpine:latest

RUN apk --no-cache add ca-certificates

RUN mkdir /app
WORKDIR /app
COPY --from=builder /go/src/github.com/ChenHanZhang/microservices-in-golang/email-service/email-service .

CMD ["./email-service"]<file_sep>/consignment-service/Dockerfile
# consignment-service/Dockerfile
# 我们使用Golang的官方镜像，它包含了所有用于构建Golang应用的依赖和工具
# 请注意`as builder`，这命名了我们这个镜像，以后可以用`builder`来指向它
FROM golang:1.13 as builder

# 将工作目录设置为当前微服务在gopath中的完整路径
WORKDIR /go/src/github.com/ChenHanZhang/microservices-in-golang/consignment-service

# 将代码复制到工作目录中
COPY . .

ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.cn

# 编译我们的二进制文件
RUN CGO_ENABLED=0 GOOS=linux go build  -o consignment-service -a -installsuffix cgo main.go repository.go handler.go datastore.go

# 在这里，我们第二次使用了FROM，它告诉Docker，我们从这里
# ==============================

# 要开始第二个构建流程
FROM alpine:latest
# 确保安全性的包
RUN apk --no-cache add ca-certificates
RUN mkdir /app
WORKDIR /app
# 在这里，我们不再直接从我们的宿主机器中直接拷贝二进制文件,
# 而是从一个叫做`builder`的容器中获取。它会从我们起先构建的镜像中
# 获得已经编译好的文件并引入到这个容器里。
COPY --from=builder /go/src/github.com/ChenHanZhang/microservices-in-golang/consignment-service/consignment-service .
# 运行二进制文件。不同的是，这个二进制文件是从另一个容器中获取的！
CMD ["./consignment-service"]<file_sep>/consignment-service/go.mod
module consignment-service

go 1.13

require (
	github.com/micro/go-micro v1.15.1
	github.com/miekg/dns v1.1.22 // indirect
	golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf // indirect
	golang.org/x/net v0.0.0-20191105084925-a882066a44e0
	golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6 // indirect
)

require (
	github.com/ChenHanZhang/microservices-in-golang-proto v1.0.3
	gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
)

replace github.com/lucas-clemente/quic-go => github.com/lucas-clemente/quic-go v0.7.1-0.20190913061013-f15a82d3fdc3
<file_sep>/user-service/Makefile
build:
	# this method has already been deprecated.
	# now using docker-compose to build container
	docker build -t user-service .

run:
	docker run -p 50053:50051 \
			-e MICRO_SERVER_ADDRESS=:50051 \
			-e MICRO_REGISTRY=mdns \
			user-service<file_sep>/Makefile
run_api_gateway:
	docker run -p 8080:8080 \
                 -e MICRO_REGISTRY=mdns \
                 microhq/micro api \
                 --handler=rpc \
                 --address=:8080 \
                 --namespace=shippy<file_sep>/consignment-service/Makefile
build:
	# this method has already been deprecated.
	# now using docker-compose to build container
	GOOS=linux GOARCH=amd64 go build
	docker build -t consignment-service .

run:
	docker run -p 50051:50051 \
		-e MICRO_SERVER_ADDRESS=:50051 \
		-e DB_HOST=mongodb:27017 --link mongodb:mongodb \
		-e MICRO_REGISTRY=mdns microservices-in-golang_consignment-service<file_sep>/consignment-service/main.go
package main

import (
	"errors"
	"fmt"
	micro "github.com/micro/go-micro"
	"github.com/micro/go-micro/client"
	"github.com/micro/go-micro/metadata"
	"github.com/micro/go-micro/server"
	"golang.org/x/net/context"
	"log"
	"os"

	pb "github.com/ChenHanZhang/microservices-in-golang-proto/consignment"
	userService "github.com/ChenHanZhang/microservices-in-golang-proto/user"
	vesselProto "github.com/ChenHanZhang/microservices-in-golang-proto/vessel"
)

const (
	defaultHost = "localhost:27017"
)

func main() {
	// Database host from the environment variables
	host := os.Getenv("DB_HOST")
	if host == "" {
		host = defaultHost
	}
	session, err := CreateSession(host)

	if err != nil {
		log.Panicf("Could not connect to datastore with host %s - %v", host, err)
	}

	// 确保在main退出前关闭会话
	defer session.Close()

	// Create a new service. Optionally include some options here.
	srv := micro.NewService(
		// This name must match the package name given in your protobuf definition
		micro.Name("go.micro.srv.consignment"),
		micro.Version("latest"),
		// 用户认证的中间件
		micro.WrapHandler(AuthWrapper),
	)

	vesselClient := vesselProto.NewVesselServiceClient("go.micro.srv.vessel", srv.Client())
	// Init will parse the command line flags.
	srv.Init()
	// Register handler
	pb.RegisterShippingServiceHandler(srv.Server(), &service{session, vesselClient})
	// Run the server
	if err := srv.Run(); err != nil {
		fmt.Println(err)
	}
}

// AuthWrapper 是一个高阶函数，它接受一个函数A，且返回一个函数B。其返回值函数接受三个参数：
// context, request 以及 response interface.
// Token 值提取于consignment-ci中定义的上下文。我们将使用 user-service 认证这个 token.
// 如果认证通过，那么函数A会被执行，否则将返回错误。
func AuthWrapper(fn server.HandlerFunc) server.HandlerFunc {
	return func(ctx context.Context, req server.Request, resp interface{}) error {
		meta, ok := metadata.FromContext(ctx)
		if !ok {
			return errors.New("no auth meta-data found in request")
		}
		// Note this is now uppercase (not entirely sure why this is...)
		token := meta["Token"]
		log.Println("Authenticating with token: ", token)
		// Auth here
		authClient := userService.NewUserServiceClient("go.micro.srv.user", client.DefaultClient)
		_, err := authClient.ValidateToken(context.Background(), &userService.Token{
			Token: token,
		})
		if err != nil {
			return err
		}
		err = fn(ctx, req, resp)
		return err
	}
}<file_sep>/consignment-cli/Dockerfile
FROM golang:1.13 as builder

WORKDIR /go/src/github.com/ChenHanZhang/microservices-in-golang/consignment-cli

COPY . .

ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.cn

RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .

FROM alpine:latest

RUN apk --no-cache add ca-certificates

RUN mkdir /app
WORKDIR /app
COPY consignment.json /app/consignment.json
COPY --from=builder /go/src/github.com/ChenHanZhang/microservices-in-golang/consignment-cli/consignment-cli .

ENTRYPOINT ["./consignment-cli", "consignment.json", "<KEY>"]
CMD ["./consignment-cli"]<file_sep>/consignment-cli/Makefile
build:
	# this method has already been deprecated.
	# now using docker-compose to build container
	GOOS=linux GOARCH=amd64 go build
	docker build -t consignment-cli .

run:
	docker run -e MICRO_REGISTRY=mdns \
	-e DB_HOST=mongodb:27017 --link mongodb:mongodb microservices-in-golang_consignment-cli
<file_sep>/email-service/main.go
package main

import (
	"context"
	pb "github.com/ChenHanZhang/microservices-in-golang-proto/user"
	micro "github.com/micro/go-micro"
	"log"
)

const topic = "user.created"

type Subscriber struct {
}

func (sub *Subscriber) Process(ctx context.Context, user *pb.User) error {
	log.Println("Picked up a new message")
	log.Println("Sending email to:", user.Name)
	return nil
}

func main() {
	srv := micro.NewService(
		micro.Name("go.micro.srv.email"),
		micro.Version("latest"))
	srv.Init()

	pubSub := srv.Server().Options().Broker

	if err := pubSub.Connect(); err != nil {
		log.Fatalf("broker connect error: %v\n", err)
	}

	// 订阅消息
	err := micro.RegisterSubscriber(topic, srv.Server(), new(Subscriber))

	if err = srv.Run(); err != nil {
		log.Fatal(err)
	}
}
<file_sep>/user-service/token_service.go
package main

import (
	"errors"
	pb "github.com/ChenHanZhang/microservices-in-golang-proto/user"
	"github.com/dgrijalva/jwt-go"
	"time"
)

var (
	key = []byte("mySuperSecretKey")
)

// CustomClaims 是一个自定义的元数据，它的哈希值会被当作JWT的第二个部分
type CustomClaims struct {
	User *pb.User
	jwt.StandardClaims
}

type Authable interface {
	Decode(token string) (*CustomClaims, error)
	Encode(user *pb.User) (string, error)
}

type TokenService struct {
	repo Repository
}

func (s *TokenService) Decode(tokenString string) (*CustomClaims, error) {
	token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) {
		return key, nil
	})

	if token == nil {
		return nil, errors.New("need a token to access")
	}

	if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
		return claims, nil
	} else {
		return nil, err
	}
}

func (s *TokenService) Encode(user *pb.User) (string, error)  {

	expireToken := time.Now().Add(time.Hour * 72).Unix()
	// 生成 claims
	claims := CustomClaims{
		user,
		jwt.StandardClaims{
			ExpiresAt: expireToken,
			Issuer:    "go.micro.srv.user",
		},
	}
	// 生成 token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 返回签名后的 token
	return token.SignedString(key)
}<file_sep>/consignment-service/handler.go
package main

import (
	"golang.org/x/net/context"
	"gopkg.in/mgo.v2"
	"log"

	pb "github.com/ChenHanZhang/microservices-in-golang-proto/consignment"
	vesselProto "github.com/ChenHanZhang/microservices-in-golang-proto/vessel"
)

type service struct {
	session *mgo.Session
	vesselClient vesselProto.VesselServiceClient
}

// 请注意session.Clone()，为什么要Clone?
func (s *service) GetRepo() Repository {
	return &ConsignmentRepository{s.session.Clone()}
}

func (s *service) CreateConsignment(ctx context.Context, req *pb.Consignment, res *pb.Response) error {
	repo := s.GetRepo()
	defer repo.Close()

	log.Println("creating consignment...")
	log.Println("Looking for a available vessel..")

	vesselResponse, err := s.vesselClient.FindAvailable(context.Background(), &vesselProto.Specification{
		MaxWeight: req.Weight,
		Capacity: int32(len(req.Containers)),
	})
	if err != nil {
		// TODO: 这里有必要将错误给 Wrap 上吗
		log.Printf("vesselClient cause an error: %v\n", err)
		return err
	}
	log.Printf("Found vessel: %s \n", vesselResponse.Vessel.Name)
	// We set the VesselId as the vessel we got back from our
	// vessel service
	req.VesselId = vesselResponse.Vessel.Id
	// Save our consignment
	err = repo.Create(req)
	if err != nil {
		return err
	}
	// Return matching the `Response` message we created in our
	// protobuf definition.
	res.Created = true
	res.Consignment = req
	return nil
}

func (s *service) GetConsignments(ctx context.Context, req *pb.GetRequest, res *pb.Response) error {
	repo := s.GetRepo()
	defer repo.Close()
	consignments, err := repo.GetAll()
	if err != nil {
		return err
	}
	res.Consignments = consignments
	return nil
}<file_sep>/vessel-service/Makefile
build:
	# this method has already been deprecated.
	# now using docker-compose to build container
	GOOS=linux GOARCH=amd64 go build
	docker build -t vessel-service .

run:
	docker run -p 50052:50052 -e MICRO_SERVER_ADDRESS=:50051 -e MICRO_REGISTRY=mdns \
		-e DB_HOST=mongodb:27017 --link mongodb:mongodb microservices-in-golang_vessel-service<file_sep>/user-cli/go.mod
module user-cli

go 1.13

require (
	github.com/ChenHanZhang/microservices-in-golang-proto v1.0.3
	github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
	github.com/gogo/protobuf v1.3.1 // indirect
	github.com/json-iterator/go v1.1.8 // indirect
	github.com/lucas-clemente/quic-go v0.13.0 // indirect
	github.com/micro/go-micro v1.15.1
	github.com/miekg/dns v1.1.22 // indirect
	github.com/nats-io/nats.go v1.9.1 // indirect
	github.com/nats-io/nkeys v0.1.2 // indirect
	go.uber.org/multierr v1.4.0 // indirect
	go.uber.org/zap v1.12.0 // indirect
	golang.org/x/crypto v0.0.0-20191106202628-ed6320f186d4 // indirect
	golang.org/x/net v0.0.0-20191105084925-a882066a44e0
	golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd // indirect
	golang.org/x/tools v0.0.0-20191107010934-f79515f33823 // indirect
	google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect
)
<file_sep>/consignment-service/utils/tools.go
package utils

import (
	"fmt"
	"time"
)

func PrintWithTime(s string)  {
	o := time.Now().String() + ":" + s
	fmt.Println(o)
}
<file_sep>/vessel-service/go.mod
module vessel-service

go 1.13

require (
	github.com/ChenHanZhang/microservices-in-golang-proto v1.0.1
	github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // indirect
	github.com/gogo/protobuf v1.3.1 // indirect
	github.com/json-iterator/go v1.1.8 // indirect
	github.com/marten-seemann/qtls v0.4.1 // indirect
	github.com/micro/go-micro v1.15.1
	github.com/miekg/dns v1.1.22 // indirect
	github.com/nats-io/nats.go v1.9.1 // indirect
	github.com/nats-io/nkeys v0.1.2 // indirect
	go.uber.org/zap v1.12.0 // indirect
	golang.org/x/crypto v0.0.0-20191029031824-8986dd9e96cf // indirect
	golang.org/x/net v0.0.0-20191101175033-0deb6923b6d9
	golang.org/x/sys v0.0.0-20191104094858-e8c54fb511f6 // indirect
	golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5
	google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6 // indirect
	gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
)

replace github.com/lucas-clemente/quic-go => github.com/lucas-clemente/quic-go v0.7.1-0.20190913061013-f15a82d3fdc3
<file_sep>/user-service/main.go
package main

import (
	"fmt"
	pb "github.com/ChenHanZhang/microservices-in-golang-proto/user"
	"github.com/micro/go-micro"
	"log"
)

func main() {

	db, err := CreateConnection()
	if err != nil{
		log.Fatalf("Could not coonect to DB: %v", err)
	}
	defer db.Close()

	db.AutoMigrate(&pb.User{})

	repo := &UserRepository{db}

	tokenService := &TokenService{repo}

	srv := micro.NewService(
			micro.Name("go.micro.srv.user"),
			micro.Version("latest"),
		)

	// 会自动读取命令行参数
	srv.Init()

	publisher := micro.NewPublisher(topic, srv.Client())

	pb.RegisterUserServiceHandler(srv.Server(), &service{repo, tokenService, publisher})

	if err := srv.Run(); err != nil {
		fmt.Println(err)
	}
}<file_sep>/consignment-cli/cli.go
package main

import (
	pb "github.com/ChenHanZhang/microservices-in-golang-proto/consignment"
	"github.com/micro/go-micro/metadata"

	"context"
	"encoding/json"
	"errors"
	microclient "github.com/micro/go-micro/client"
	"github.com/micro/go-micro/config/cmd"
	"io/ioutil"
	"log"
	"os"
)

const (
	ADDRESS = "localhost:50051"
	DEFAULT_INFO_FILE = "consignment.json"
)

// 读取 consignment.json 中的货物信息
func parseFile(fileName string) (*pb.Consignment, error) {
	data, err := ioutil.ReadFile(fileName)
	if err != nil {
		return nil, err
	}
	var consignment *pb.Consignment
	err = json.Unmarshal(data, &consignment)
	if err != nil {
		return nil, errors.New("consignment.json file content error")
	}
	return consignment, nil
}

func main() {

	err := cmd.Init()

	// 服务发现 => pb.NewShippingService TODO: 这个方法封装了什么？
	client := pb.NewShippingServiceClient("go.micro.srv.consignment", microclient.DefaultClient)

	infoFile := DEFAULT_INFO_FILE

	if len(os.Args) < 3 {
		log.Fatal(errors.New("no enough parms."))
	}

	infoFile = os.Args[1]
	token := os.Args[2]

	log.Println("use token: ", token)

	// 解析货物
	consignment, err := parseFile(infoFile)
	if err != nil {
		log.Fatalf("parse info file error: %v", err)
	}

	// 创建一个包含自定义token 的上下文
	// 这个上下文会在我们调用consignment-service时被传入
	ctx := metadata.NewContext(context.Background(), map[string]string{
		"token": token,
	})

	// 调用 RPC
	// 将货物存储到自己的仓库里
	resp, err := client.CreateConsignment(ctx, consignment)
	if err != nil {
		log.Fatalf("create consignment error: %v", err)
	}

	log.Printf("created: %t", resp.Created)

	// 列出当前所有托运的货物
	resp, err = client.GetConsignments(ctx, &pb.GetRequest{})
	if err != nil {
		log.Fatalf("failed to list consignments: %v", err)
	}
	for _, c := range resp.Consignments{
		log.Printf("%+v", c)
	}
}<file_sep>/user-service/go.mod
module user-service

go 1.13

require (
	github.com/ChenHanZhang/microservices-in-golang-proto v1.0.3 // indirect
	github.com/jinzhu/gorm v1.9.11
)
<file_sep>/vessel-service/Dockerfile
FROM golang:1.13 as builder

WORKDIR /go/src/github.com/ChenHanZhang/microservices-in-golang/vessel-service

COPY . .

ENV GO111MODULE=on
ENV GOPROXY=https://goproxy.io

RUN go get
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .

FROM alpine:latest

RUN apk --no-cache add ca-certificates

RUN mkdir /app
WORKDIR /app
COPY --from=builder /go/src/github.com/ChenHanZhang/microservices-in-golang/vessel-service/vessel-service .

CMD ["./vessel-service"]<file_sep>/email-service/go.mod
module email-service

go 1.13

require (
	github.com/ChenHanZhang/microservices-in-golang-proto v1.0.3
	github.com/micro/go-micro v1.15.1
)

languages:
Makefile
Markdown
Dockerfile
Go Module
Go

repo_language: Makefile

repo_name: ChenHanZhang/microservices-in-golang


text:
<file_sep>import urllib
import urllib2
import json

def postToAPI(api_url,action,charset,postData):
    reqdata = {'action':action,'charset':charset,'postData':postData}
    headers = {'Content-Type': 'application/json'}
    req = urllib2.Request(url = api_url,headers=headers,data =json.dumps(reqdata))
    res_data = urllib2.urlopen(req)

postToAPI('http://1192.168.3.11:1858/postDataApi','print','utf-8',{'headers': {'Accept': ' text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'Connection': ' close', 'User-Agent': ' Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36', 'Host': ' www.t00ls.net', 'Cache-Control': ' max-age=0', 'Upgrade-Insecure-Requests': ' 1', 'Accept-Language': ' zh-CN,zh;q=0.9', 'line1': 'GET /index.php HTTP/1.1'}, 'body': '', 'url':u'https://www.t00ls.net:443/index.php', 'protocol': u'https', 'port': 443, 'host': u'www.t00ls.net'})<file_sep>#!/usr/bin/python
# author:Shelly
# time:2018-03-28

def getRequestInfo(messageIsRequest,messageInfo,helpers):
    result = {}
    if messageIsRequest:
        httpService = messageInfo.getHttpService()
        host = httpService.getHost() #<type 'unicode'>
        port = httpService.getPort() #<type 'int'>
        protocol = httpService.getProtocol()#<type 'unicode'>
        request = messageInfo.getRequest()#<type 'java.util.ArrayList'>
        analyzeRequest = helpers.analyzeRequest(httpService,request)
        headers = analyzeRequest.getHeaders()
        body = request[analyzeRequest.getBodyOffset():]
        body_str = body.tostring()#<type 'str'>
        url = analyzeRequest.getUrl() #<type 'java.net.URL'>
        result = {'url':url,'host':host,'port':port,'protocol':protocol,'headers':headers,'body':body_str}
        return result
    else:
        print 'not request'
        pass

def getResponseInfo(messageIsRequest,messageInfo,helpers):
    result = {}
    if not messageIsRequest:
        response = messageInfo.getResponse()
        analyzedResponse = helpers.analyzeResponse(response)
        headers = analyzedResponse.getHeaders()
        body = response[analyzedResponse.getBodyOffset():]
        body_str = body.tostring()
        result = {'headers':headers,'body':body_str}
        return result
    else :
        print 'not response'
        pass

def changeRequest(messageInfo,helpers,new_headers,new_body):
    messageInfo.setRequest(helpers.buildHttpMessage(new_headers, new_body))

def changeResponse(messageInfo,helpers,new_headers,new_body):
    messageInfo.setResponse(helpers.buildHttpMessage(new_headers, new_body))

def sendDataToApi(messageIsRequest,messageInfo,helpers):
    if messageIsRequest:
        httpService = messageInfo.getHttpService()
        host = httpService.getHost() #<type 'unicode'>
        port = httpService.getPort() #<type 'int'>
        protocol = httpService.getProtocol()#<type 'unicode'>
        request = messageInfo.getRequest()#<type 'java.util.ArrayList'>
        analyzeRequest = helpers.analyzeRequest(httpService,request)
        headers = analyzeRequest.getHeaders()
        body = request[analyzeRequest.getBodyOffset():]
        body_str = body.tostring()#<type 'str'>
        url = analyzeRequest.getUrl() #<type 'java.net.URL'>

        # format headers from ARRAY to DICT
        post_headers = {}
        for i in range(0,len(headers)-1):
            j = headers[i]
            if i == 0 :
                post_headers['line1'] = str(j)
            else:
                j_split_array = j.split(':')
                j_split_array_len = len(j_split_array)
                if j_split_array_len == 2 :
                    post_headers[str(j_split_array[0])] = str(j_split_array[1])
                else:
                    head_value = ''
                    for k in range(1,j_split_array_len-1):
                        head_value = head_value + str(j_split_array[k])
                    post_headers[str(j_split_array[0])] = head_value

        postToAPI_data = {'url':str(url),'host':str(host),'port':str(port),'protocol':str(protocol),'headers':post_headers,'body':body_str}

        #if requests not in blacklist,send to api
        def getReqType(post_headers):
            url_path = post_headers['line1'].split(' ')[1]
            if '.' in url_path :
                return url_path.split('.')[1]
            else :
                return ' '
        reqType_blackList = ['htm','html','js','png','jpg']
        if getReqType(post_headers) not in reqType_blackList:
            postToAPI('http://127.0.0.1:1858/postDataApi','print','utf-8',postToAPI_data)

sendDataToApi(messageIsRequest,messageInfo,helpers)

'''
if messageIsRequest:
    request = getRequestInfo(messageIsRequest,messageInfo,helpers)
    new_requestHeaders = request['headers']
    new_requestBody = request['body']
    changeRequest(messageInfo,helpers,new_requestHeaders,new_requestBody)

if not messageIsRequest:
    response = getResponseInfo(messageIsRequest,messageInfo,helpers)
    new_responseHeaders = response['headers']
    new_responseBody = 'hello ! burp script!'
    changeResponse(messageInfo,helpers,new_responseHeaders,new_responseBody)
'''<file_sep>#! /usr/bin/env python3
# encoding: utf-8
# author:Shelly
# time:2019-01-14
from sys import path
from  http.server import HTTPServer,BaseHTTPRequestHandler
import demjson

'''
只接收post数据：
{'action':'print','charset':'utf-8','postData':{'url':url,'host':host,'port':port,'protocol':protocol,'headers':headers_dict,'body':body_str}}
'''

class ServerHTTP(BaseHTTPRequestHandler):

	#默认回显
	def creat_wfile(self):
		self.send_response(200)
		self.send_header('Content-type','text/html; charset=utf-8')
		self.send_header('Content-Length',str(len(self.data)))
		self.end_headers()
		self.wfile.write(bytes(self.data, encoding='utf-8'))

    #处理get请求：不支持
	def do_GET(self):
		self.data = '{"status":1,"error":"Only supprt POST"}'
		self.creat_wfile()

	#接收数据
	def do_POST(self):
		self.webName = str(self.path.split('/')[1])
		if self.postDataApi():
			length = int(self.headers['content-length'])
			postData = self.rfile.read(length)
			print (postData)
			print (demjson.decode(postData))
			self.data = '{"status":0,"error":""}'
			self.creat_wfile()
		else:
			self.data = '{"status":1,"error":"API not exist!"}'
			self.creat_wfile()

	#api
	def postDataApi(self):
		if self.webName == 'postDataApi':
			return True
		else:
			return False

def start_server(port):
	http_server = HTTPServer(('', int(port)),ServerHTTP)
	http_server.serve_forever()

#在1858端口开启http服务
if __name__ == "__main__":
	start_server(1858)

str123 = "{'url':"+url+",'host':"+host+",'port':"+port+",'protocol':"+protocol+",'headers':"+headers+",'body':"+body_str+"}"
<file_sep>1、简介
	通过burpsuit插件（scripter），抓取burpsuit符合规则的请求，将其发送到api接口（http服务），并调用api接口上的扫描模块进行扫描。

2、使用方法

	2、1 修改scripter插件
		将修改后burpscripter.py放到原位置，主要是在插件里新添了函数postToAPI

	2、2 添加基于burp的数据采集
		将burp_post.py的代码复制到scripter插件的输入框

		主要实现以下2个功能：
		i 统一接受数据格式：
		{'action':'print','charset':'utf-8','postData':postData_dict}
		其中：
		postData_dict:
		{'url':url,'host':host,'port':port,'protocol':protocol,'headers':headers_dict,'body':body_str}
		action:标志收到数据后，做何种处理
		如只进行sql注入扫描，还是进行全部扫描
		charset：编码方式，默认设为utf-8，此外还有iso、gbk
		postData_dict：传递的http请求数据
		url：网址
		host：主机
		port：端口
		protocol：协议
		headers：http头，请设置为字典类型
		body：数据内容，请设置为字符串类型

		ii 筛选符合格式的请求：
		目前采用黑名单筛选：后缀不在黑名单的，发送到api接口
		reqType_blackList = ['htm','html','js','png','jpg']

	2、3 开启api服务
		python3 main.py

3、开发进度

	2019/01/14
	完成基于burp的数据采集初版
	完成main.py初版：目前直接对接收到数据进行打印，未做其他处理
	下一步计划：添加data模块，采用sqlite3对接收的数据进行排序、存储

branch_name: refs/heads/master

languages: Markdown Python

repo_language: Markdown

repo_name: jellyHero/antiMage


text:
<file_sep>port = 1433
databaseName = dbWaterworksAdministration
userName = sa
password = <PASSWORD>

repo_language: INI

repo_name: Kristoffer-ProgGod/Waterworks


text:
<repo_name>mmarrow/Angular2-HeroEditor<file_sep>/README.md
# Angular2-HeroEditor
App from Angular 2 Documentation - Using to learn Angular2


text:
<file_sep># broccoli-rework [![Build Status](https://travis-ci.org/kevva/broccoli-rework.svg?branch=master)](https://travis-ci.org/kevva/broccoli-rework)

> Preprocess CSS with [Rework](https://github.com/reworkcss/rework)

## Install

```bash
$ npm install --save broccoli-rework
```

## Usage

```js
var rework = require('broccoli-rework');

tree = rework(tree, { use: function (css) {
    css.use(rework.colors());
}});
```

## API

### rework(tree, opts)

Initialize a new rework with the given string of regular CSS. Optionally supply
an object with options as the last argument.

## Options

### use

Type: `Function`
Default: `undefined`

Accepts a function that gives you the ability to interact with rework before
compiling. Useful for adding on plugins, etc.

## License

MIT © [<NAME>](https://github.com/kevva)

repo_name: SlexAxton/broccoli-rework


text:
<repo_name>bongsoos/ProgrammingAssignment2<file_sep>/cachematrix.R
## Put comments here that give an overall description of what your
## functions do

## Write a short comment describing this function
# makeCacheMatrix: This function creates a special "matrix" object
# that can cache its inverse.
makeCacheMatrix <- function(x = matrix()) {

    inv <- NULL
    get <- function() {
        x
    }
    set <- function(y) {
        x <<- y
        inv <<- NULL
    }
    getinv <- function() {
        inv
    }
    setinv <- function(y) {
        inv <<- y
    }
    list(set=set, get=get, setinv=setinv, getinv=getinv)

}

## Write a short comment describing this function
# cacheSolve: This function computes the inverse of the special "matrix"
# returned by makeCacheMatrix above. If the inverse has already been
# calculated (and the matrix has not changed), then the cachesolve should
# retrieve the inverse from the cache.
cacheSolve <- function(x, ...) {
    ## Return a matrix that is the inverse of 'x'
    x_inv <- x$getinv()
    if (!is.null(x_inv)) {
        print("this is cached inverse matrix")
        return(x_inv)
    }
    x_mat <- x$get()
    x_inv <- solve(x_mat,...)
    x$setinv(x_inv)
    x_inv
}

repo_language: R


text:
<file_sep>package com.mht.service.service;

import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.mht.service.dao.BillDetailVOMapper;
import com.mht.service.dao.BillVOMapper;
import com.mht.service.vo.BillDetailVO;
import com.mht.service.vo.BillVO;

/***
 * @Author: <NAME>
 * @Description:
 * @Date:Created in 下午 12:04 2018/3/17
 */
@Service
public class BillService {

	@Autowired
	private BillVOMapper billVOMapper;

	@Autowired
	private BillDetailVOMapper billDetailVOMapper;

	/**
	 * @Author: <NAME>
	 * @Description:
	 * @Date: 下午 09:58 2018/3/18
	 */
	public boolean saveBill(BillVO billVO) {
		try {
			billVOMapper.insert(billVO);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	public boolean saveDetailBill(BillDetailVO billVO) {
		try {
			billDetailVOMapper.insert(billVO);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * @return
	 */
	public List<BillVO> queryBillList() {
		return billVOMapper.queryBillList();
	}

	/**
	 * @return
	 */
	public List<BillDetailVO> queryBillDetailList(String id) {
		return billDetailVOMapper.queryBillDetailList(id);
	}

	/**
	 * @param vo
	 * @return
	 */
	public boolean updateBill(BillVO vo) {
		try {
			billVOMapper.update(vo);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * @param billIds
	 * @return
	 */
	public Integer deleteBill(String user, Date deleteDate, List<String> billIds) {
		// TODO Auto-generated method stub
		return billVOMapper.deleteBill(user, deleteDate, billIds);
	}

}
<file_sep>/**
 * Hello.java
 * 2017年9月13日
 */
package com.mht.service.controller;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author CY
 * @date 2017年9月13日
 */
@Controller
public class Hello {

	private final Logger logger = LoggerFactory.getLogger(this.getClass());

//	@RequestMapping("/")
//	public String hello() {
//		logger.info("helllollllllllllllllllllllllllllll");
//		return "Hello world!!!!";
//	}

	@RequestMapping("/HelloWorld")
	public String helloHtml(Map<String, Object> map) {

		map.put("hello", "我们是from TemplateController.helloHtml");
		return "/HelloWorld";
	}
}
<file_sep>/**
 * UserController.java
 * 2017年9月14日
 */
package com.mht.service.controller;

import org.springframework.web.bind.annotation.RestController;

/**
 * @author CY
 * @date 2017年9月14日
 */
@RestController
public class UserController {

}
<file_sep>package com.mht.service.controller;

import java.util.Date;
import java.util.List;
import java.util.UUID;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.mht.service.service.BillService;
import com.mht.service.vo.BillDetailVO;
import com.mht.service.vo.BillVO;

/***
 * @Author: <NAME>
 * @Description:
 * @Date:Created in 下午 12:05 2018/3/17
 */
@RestController
public class BillController {

	@Autowired
	private BillService billService;

	@GetMapping("/addBill")
	public boolean addBill(BillVO vo) {
		vo.setBillId(UUID.randomUUID().toString());
		vo.setCreateUser("muhaitao");
		vo.setCreateTime(new Date());
		return billService.saveBill(vo);
	}

	@PostMapping("/deleteBill")
	public Integer deleteBill(@RequestParam("billIds") List<String> billIds) {
		return billService.deleteBill("chenyan", new Date(), billIds);
	}

	@PostMapping("/updateBill")
	public boolean updateBill(BillVO vo) {
		return billService.updateBill(vo);
	}

	@PostMapping("/saveDetailBill")
	public boolean saveDetailBill(BillDetailVO vo) {
		return billService.saveDetailBill(vo);
	}

	@GetMapping("/queryBillList")
	public List<BillVO> queryBillList() {
		return billService.queryBillList();
	}

	@GetMapping("/queryBillDetailList")
	public List<BillDetailVO> queryBillDetailList(String billDetailId) {
		List<BillDetailVO> list = billService.queryBillDetailList(billDetailId);
		return list;
	}
}
<file_sep>$(function () {

    //1.初始化Table
    var oTable = new TableInit();
    oTable.Init();

    //2.初始化Button的点击事件
    var oButtonInit = new ButtonInit();
    oButtonInit.Init();

    //禁用空白处点击关闭
    $('#addModel').modal({
  	  backdrop: 'static',
  	  keyboard: true,//禁止键盘
  	  show:false
     });

    centerModals();

    //页面大小变化是仍然保证模态框水平垂直居中
    $(window).on('resize', centerModals);

    $('form').submit(function (event) {
        event.preventDefault();
        var form = $(this);
        if (!form.hasClass('fupload')) {
          //普通表单
          $.ajax({
            type: form.attr('method'),
            url: form.attr('action'),
            data: form.serialize()
          }).success(function () {
             $('#closeBtnForAddBill').click();
             refreshList();
             oTable.ToolTip("success");
          }).fail(function (jqXHR, textStatus, errorThrown) {
        	  oTable.ToolTip("error");
          });
        }
    });

    //页面删除操作
    $("#btn_delete").on("click",function(){
    	var deleteIdArray = [];
        //收集页面中被选中的数据项
        $("input[name='btSelectItem']").each(function(){
            if($(this).is(':checked')){
            	var billId = $(this).parent().parent().attr("data-uniqueid");
            	deleteIdArray.push(billId);
            }
        });
        if($.isEmptyObject(deleteIdArray))
        {
        	alert("请选中所要删除的数据项");
        	return;
        }
        $.ajax({
            type: "POST",
            url: "/imht-web-service/deleteBill",
            data: { billIds:deleteIdArray.toString()},
            success: function (data) {
            	refreshList();
            	if(data > 0){
            		oTable.ToolTip("success");
            	}
            	else{
            		oTable.ToolTip("error");
        		}
            },
            error: function () {
            	oTable.ToolTip("error");
            },
            complete: function () {

            }

        });
    });

});

//模态框居中
function centerModals() {
　　$('#addModal').each(function(i) {
　　　　var $clone = $(this).clone().css('display','block').appendTo('body');
　　　　var top = Math.round(($clone.height() - $clone.find('.modal-content').height()) / 2);
　　　　top = top > 0 ? top : 0;
　　　　$clone.remove();
　　　　$(this).find('.modal-content').css("margin-top", top);
　　});
};

//刷新表格数据
function refreshList(){
    $.ajax({
        type: "get",
        url: "/imht-web-service/queryBillList",
        data: {},
        success: function (data) {
            $("#accountManage").bootstrapTable('refresh', data);
        },
        error: function () {

        },
        complete: function () {

        }

    });
}

function timestampToTime(timestamp) {
    var date = new Date(timestamp);//时间戳为10位需*1000，时间戳为13位的话不需乘1000
    Y = date.getFullYear() + '-';
    M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1) + '-';
    D = date.getDate() + ' ';
    h = date.getHours() + ':';
    m = date.getMinutes() + ':';
    s = date.getSeconds();
    return Y+M+D+h+m+s;
}

var TableInit = function () {
    var oTableInit = new Object();
    //初始化Table
    oTableInit.Init = function () {
        $('#accountManage').bootstrapTable({
            url: '/imht-web-service/queryBillList',              //请求后台的URL（*）
            method: 'get',                      //请求方式（*）
            toolbar: '#toolbar',                //工具按钮用哪个容器
            striped: true,                      //是否显示行间隔色
            cache: false,                       //是否使用缓存，默认为true，所以一般情况下需要设置一下这个属性（*）
            pagination: true,                   //是否显示分页（*）
            sortable: false,                     //是否启用排序
            sortOrder: "asc",                   //排序方式
            queryParams: oTableInit.queryParams,//传递参数（*）
            sidePagination: "client",           //分页方式：client客户端分页，server服务端分页（*）
            pageNumber:1,                       //初始化加载第一页，默认第一页
            pageSize: 10,                       //每页的记录行数（*）
            pageList: [10, 25, 50, 100],        //可供选择的每页的行数（*）
            search: true,                       //是否显示表格搜索，此搜索是客户端搜索，不会进服务端，所以，个人感觉意义不大
            strictSearch: true,
            showColumns: true,                  //是否显示所有的列
            showRefresh: true,                  //是否显示刷新按钮
            minimumCountColumns: 2,             //最少允许的列数
            clickToSelect: true,                //是否启用点击选中行
            height: 500,                        //行高，如果没有设置height属性，表格自动根据记录条数觉得表格高度
            uniqueId: "billId",                     //每一行的唯一标识，一般为主键列
            showToggle:true,                    //是否显示详细视图和列表视图的切换按钮
            cardView: false,                    //是否显示详细视图
            detailView: true,                   //是否显示父子表
            columns: [{
                checkbox: true
            }, {
                field: 'billName',
                title: '账目名称',
                editable:true
            }, {
                field: 'billDesc',
                title: '账目描述',
                editable:true
            }, {
                field: 'createTime',
                title: '创建时间',
                formatter: function indexFormatter(value, row, index) {//格式化时间
                    return timestampToTime(value);
                }
            }, {
                field: 'createUser',
                title: '创建人'
            }],
          //注册加载子表的事件。注意下这里的三个参数！
            onExpandRow: function (index, row, $detail) {
            	oTableInit.InitSubTable(index, row, $detail);
            	setTimeout(function(){
	            	var addBtnHtml = "<button type='button' class='btn btn-default billDetailAddBtn' data-toggle='modal' data-target='#addModal'>"
	                +"新增</button>";
	            	$("table[class='table table-hover']").find("thead").find("tr").each(function(){
	            		if(!$(this).children().hasClass("billDetailAddBtn"))
	            		{
		            		$(this).append(addBtnHtml);
	            		}
	            	});
            	},10);
            },
            //编辑保存事件
            onEditableSave: function (field, row, oldValue, $el) {
                $.ajax({
                    type: "post",
                    url: "/imht-web-service/updateBill",
                    data: { billId:row.billId,
                    	billName:row.billName,
                    	billDesc:row.billDesc},
                    success: function (data, status) {
                    	oTableInit.ToolTip("success");
                    },
                    error: function () {
                    	oTableInit.ToolTip("error");
                    },
                    complete: function () {

                    }

                });
            }
        });
    };

    //得到查询的参数
    oTableInit.queryParams = function (params) {
        var temp = {   //这里的键的名字和控制器的变量名必须一直，这边改动，控制器也需要改成一样的
            limit: params.limit,   //页面大小
            offset: params.offset,  //页码
            departmentname: $("#txt_search_departmentname").val(),
            status: $("#txt_search_statu").val(),
            search: params.search
        };
        return temp;
    };

    //操作提示框
    oTableInit.ToolTip = function(type){
    	if("success" == type){
	    	$('#mySuccessAlert').show();
	    	setTimeout(function(){
	    		$('#mySuccessAlert').hide();
	    	},1000);
    	}else{
	    	$('#myErrorAlert').show();
	    	setTimeout(function(){
	    		$('#myErrorAlert').hide();
	    	},1000);
		}
    },

   //初始化子表格(无线循环)
    oTableInit.InitSubTable = function (index, row, $detail) {
        var parentId = row.billId;
        var cur_table = $detail.html('

').find('table');
        $(cur_table).bootstrapTable({
            url: '/imht-web-service/queryBillDetailList',
            method: 'get',
            queryParams: { billDetailId: parentId },
            ajaxOptions: { billDetailId: parentId },
            clickToSelect: true,
            cache: false,
            detailView: false,//父子表
            uniqueId: "billDetailId",
            pageSize: 10,
            pageList: [10, 25],
            columns: [
            	{
                field: 'operator',
                title: '操作'
            },
            	{
                field: 'currentYear',
                title: '当前年份'
            },
            	{
                field: 'currentMonth',
                title: '当前月份'
            },
            	{
                field: 'preMonthPrincipal',
                title: '上月本息和',
                editable:true
            }, {
                field: 'currentMonthPrincipal',
                title: '当月本息和',
                editable:true
            }, {
                field: 'currentMonthInput',
                title: '当月投入',
                editable:true
            }, {
                field: 'currentMonthIncome',
                title: '当月收益',
                editable:true
            } ],
            //无线循环取子表，直到子表里面没有记录
            onExpandRow: function (index, row, $Subdetail) {
            	oTableInit.InitSubTable(index, row, $Subdetail);
            },
            //编辑保存事件
            onEditableSave: function (field, row, oldValue, $el) {
                $.ajax({
                    type: "post",
                    url: "/imht-web-service/saveDetailBill",
                    data: {billId:row.billId,
                    	currentYear:row.currentYear,
                    	currentMonth:row.currentMonth,
                    	billDetailId:row.billDetailId,
                    	preMonthPrincipal:row.preMonthPrincipal,
                    	currentMonthPrincipal:row.currentMonthPrincipal,
                    	currentMonthInput:row.currentMonthInput,
                    	currentMonthIncome:row.currentMonthIncome},
                    success: function (data, status) {
                    	oTableInit.ToolTip("success");
                    },
                    error: function () {
                    	oTableInit.ToolTip("error");
                    },
                    complete: function () {

                    }

                });
            }
        });
    };
    return oTableInit;
};

var ButtonInit = function () {
    var oInit = new Object();
    var postdata = {};

    oInit.Init = function () {
        //初始化页面上面的按钮事件
    };

    return oInit;
};

languages: Java JavaScript

repo_language: Java

repo_name: HaitaoMu/imht-account-book


text:
<repo_name>DataScienceUnbound/BACKUP<file_sep>/README.md
# BACKUP

## Working on the AWS, remember on the screen to do this

Detach from screen

Command: Ctrl-a and then d

Other useful commands:

    Create new window: Ctrl-a c.
    Switch windows: Ctrl-a n
    Reattach to Screen: screen -r
    See running screen processes screen -ls

#To kill the screen use this syntax, were the number is the ID
screen  -S 19988 -X quit

repo_name: DataScienceUnbound/BACKUP