<commit_before>package main

import (
	"testing"

	"github.com/buger/gor/listener"
	"github.com/buger/gor/replay"

	"time"

	"fmt"
	"net/http"
	"strconv"

	"sync/atomic"
)

func isEqual(t *testing.T, a interface{}, b interface{}) {
	if a != b {
		t.Error("Original and Replayed request not match\n", a, "!=", b)
	}
}

var envs int

type Env struct {
	Verbose bool

	ListenHandler http.HandlerFunc
	ReplayHandler http.HandlerFunc

	ReplayLimit   int
	ListenerLimit int
}

func (e *Env) start() (p int) {
	p = 50000 + envs*10

	go e.startHTTP(p, http.HandlerFunc(e.ListenHandler))
	go e.startHTTP(p+2, http.HandlerFunc(e.ReplayHandler))
	go e.startListener(p, p+1)
	go e.startReplay(p+1, p+2)

	// Time to start http and gor instances
	time.Sleep(time.Millisecond * 100)

	envs++

	return
}

func (e *Env) startListener(port int, replayPort int) {
	listener.Settings.Verbose = e.Verbose
	listener.Settings.Address = "127.0.0.1"
	listener.Settings.ReplayAddress = "127.0.0.1:" + strconv.Itoa(replayPort)
	listener.Settings.Port = port

	if e.ListenerLimit != 0 {
		listener.Settings.ReplayAddress += "|" + strconv.Itoa(e.ListenerLimit)
	}

	listener.Run()
}

func (e *Env) startReplay(port int, forwardPort int) {
	replay.Settings.Verbose = e.Verbose
	replay.Settings.Host = "127.0.0.1"
	replay.Settings.ForwardAddress = "127.0.0.1:" + strconv.Itoa(forwardPort)
	replay.Settings.Port = port

	if e.ReplayLimit != 0 {
		replay.Settings.ForwardAddress += "|" + strconv.Itoa(e.ReplayLimit)
	}

	replay.Run()
}

func (e *Env) startHTTP(port int, handler http.Handler) {
	http.ListenAndServe(":"+strconv.Itoa(port), handler)
}

func getRequest(port int) *http.Request {
	req, _ := http.NewRequest("GET", "http://localhost:"+strconv.Itoa(port)+"/test", nil)
	ck1 := new(http.Cookie)
	ck1.Name = "test"
	ck1.Value = "value"

	req.AddCookie(ck1)

	return req
}

func TestReplay(t *testing.T) {
	var request *http.Request
	received := make(chan int)

	listenHandler := func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "OK", http.StatusNotFound)
	}

	replayHandler := func(w http.ResponseWriter, r *http.Request) {
		isEqual(t, r.URL.Path, request.URL.Path)
		isEqual(t, r.Cookies()[0].Value, request.Cookies()[0].Value)

		http.Error(w, "404 page not found", http.StatusNotFound)

		if t.Failed() {
			fmt.Println("\nReplayed:", r, "\nOriginal:", request)
		}

		received <- 1
	}

	env := &Env{
		Verbose:       true,
		ListenHandler: listenHandler,
		ReplayHandler: replayHandler,
	}
	p := env.start()

	request = getRequest(p)

	_, err := http.DefaultClient.Do(request)

	if err != nil {
		t.Error("Can't make request", err)
	}

	select {
	case <-received:
	case <-time.After(time.Second):
		t.Error("Timeout error")
	}
}

func rateLimitEnv(replayLimit int, listenerLimit int) int32 {
	var processed int32

	listenHandler := func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "OK", http.StatusAccepted)
	}

	replayHandler := func(w http.ResponseWriter, r *http.Request) {
		atomic.AddInt32(&processed, 1)
		http.Error(w, "OK", http.StatusAccepted)
	}

	env := &Env{
		ListenHandler: listenHandler,
		ReplayHandler: replayHandler,
		ReplayLimit:   replayLimit,
		ListenerLimit: listenerLimit,
	}

	p := env.start()
	req := getRequest(p)

	for i := 0; i < 10; i++ {
		http.DefaultClient.Do(req)
	}

	time.Sleep(time.Millisecond * 500)

	return processed
}

func TestWithoutReplayRateLimit(t *testing.T) {
	processed := rateLimitEnv(0, 0)

	if processed != 10 {
		t.Error("It should forward all requests without rate-limiting", processed)
	}
}

func TestReplayRateLimit(t *testing.T) {
	processed := rateLimitEnv(5, 0)

	if processed != 5 {
		t.Error("It should forward only 5 requests with rate-limiting", processed)
	}
}

func TestListenerRateLimit(t *testing.T) {
	processed := rateLimitEnv(0, 3)

	if processed != 3 {
		t.Error("It should forward only 3 requests with rate-limiting", processed)
	}
}
<commit_msg>Add concurrency settings to test<commit_after>package main

import (
	"testing"

	"github.com/buger/gor/listener"
	"github.com/buger/gor/replay"

	"time"

	"fmt"
	"net/http"
	"strconv"

	"sync/atomic"
)

func isEqual(t *testing.T, a interface{}, b interface{}) {
	if a != b {
		t.Error("Original and Replayed request not match\n", a, "!=", b)
	}
}

var envs int

type Env struct {
	Verbose bool

	ListenHandler http.HandlerFunc
	ReplayHandler http.HandlerFunc

	ReplayLimit   int
	ListenerLimit int
}

func (e *Env) start() (p int) {
	p = 50000 + envs*10

	go e.startHTTP(p, http.HandlerFunc(e.ListenHandler))
	go e.startHTTP(p+2, http.HandlerFunc(e.ReplayHandler))
	go e.startListener(p, p+1)
	go e.startReplay(p+1, p+2)

	// Time to start http and gor instances
	time.Sleep(time.Millisecond * 100)

	envs++

	return
}

func (e *Env) startListener(port int, replayPort int) {
	listener.Settings.Verbose = e.Verbose
	listener.Settings.Address = "127.0.0.1"
	listener.Settings.ReplayAddress = "127.0.0.1:" + strconv.Itoa(replayPort)
	listener.Settings.Port = port

	if e.ListenerLimit != 0 {
		listener.Settings.ReplayAddress += "|" + strconv.Itoa(e.ListenerLimit)
	}

	listener.Run()
}

func (e *Env) startReplay(port int, forwardPort int) {
	replay.Settings.Verbose = e.Verbose
	replay.Settings.Host = "127.0.0.1"
	replay.Settings.ForwardAddress = "127.0.0.1:" + strconv.Itoa(forwardPort)
	replay.Settings.Port = port

	if e.ReplayLimit != 0 {
		replay.Settings.ForwardAddress += "|" + strconv.Itoa(e.ReplayLimit)
	}

	replay.Run()
}

func (e *Env) startHTTP(port int, handler http.Handler) {
	http.ListenAndServe(":"+strconv.Itoa(port), handler)
}

func getRequest(port int) *http.Request {
	req, _ := http.NewRequest("GET", "http://localhost:"+strconv.Itoa(port)+"/test", nil)
	ck1 := new(http.Cookie)
	ck1.Name = "test"
	ck1.Value = "value"

	req.AddCookie(ck1)

	return req
}

func TestReplay(t *testing.T) {
	var request *http.Request
	received := make(chan int)

	listenHandler := func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "OK", http.StatusNotFound)
	}

	replayHandler := func(w http.ResponseWriter, r *http.Request) {
		isEqual(t, r.URL.Path, request.URL.Path)
		isEqual(t, r.Cookies()[0].Value, request.Cookies()[0].Value)

		http.Error(w, "404 page not found", http.StatusNotFound)

		if t.Failed() {
			fmt.Println("\nReplayed:", r, "\nOriginal:", request)
		}

		received <- 1
	}

	env := &Env{
		Verbose:       true,
		ListenHandler: listenHandler,
		ReplayHandler: replayHandler,
	}
	p := env.start()

	request = getRequest(p)

	_, err := http.DefaultClient.Do(request)

	if err != nil {
		t.Error("Can't make request", err)
	}

	select {
	case <-received:
	case <-time.After(time.Second):
		t.Error("Timeout error")
	}
}

func rateLimitEnv(replayLimit int, listenerLimit int, connCount int) int32 {
	var processed int32

	listenHandler := func(w http.ResponseWriter, r *http.Request) {
		http.Error(w, "OK", http.StatusAccepted)
	}

	replayHandler := func(w http.ResponseWriter, r *http.Request) {
		atomic.AddInt32(&processed, 1)
		http.Error(w, "OK", http.StatusAccepted)
	}

	env := &Env{
		ListenHandler: listenHandler,
		ReplayHandler: replayHandler,
		ReplayLimit:   replayLimit,
		ListenerLimit: listenerLimit,
	}

	p := env.start()
	req := getRequest(p)

	for i := 0; i < connCount; i++ {
		go func() {
			http.DefaultClient.Do(req)
		}()
	}

	time.Sleep(time.Millisecond * 500)

	return processed
}

func TestWithoutReplayRateLimit(t *testing.T) {
	processed := rateLimitEnv(0, 0, 10)

	if processed != 10 {
		t.Error("It should forward all requests without rate-limiting", processed)
	}
}

func TestReplayRateLimit(t *testing.T) {
	processed := rateLimitEnv(5, 0, 10)

	if processed != 5 {
		t.Error("It should forward only 5 requests with rate-limiting", processed)
	}
}

func TestListenerRateLimit(t *testing.T) {
	processed := rateLimitEnv(0, 3, 100)

	if processed != 3 {
		t.Error("It should forward only 3 requests with rate-limiting", processed)
	}
}
<|endoftext|>


<commit_before>package wspacego

import (
	. "github.com/r7kamura/gospel"
	"path"
	"runtime"
	"testing"
)

func TestInterpretor(t *testing.T) {
	Describe(t, "インタープリターのテスト", func() {
		data := []byte{'A', ' ', 'B', '\t', '\r', '\n'}
		Context("インスタンス生成", func() {
			It("インスタンスが生成できること", func() {
				actual := NewInterpreter(data)
				Expect(actual).To(Exist)
				Expect(actual.origin).To(Equal, data)
			})
		})
		Context("不要な文字を排除する関数", func() {
			It("不要なデータ以外排除されていること", func() {
				sut := NewInterpreter(data)
				sut.filter()
				Expect(sut.source).To(Equal, []byte{' ', '\t', '\n'})
			})
			It("不要なデータ以外排除されていること（改行を増やす）", func() {
				data = append(data, '\n')
				sut := NewInterpreter(data)
				sut.filter()
				Expect(sut.source).To(Equal, []byte{' ', '\t', '\n', '\n'})
			})
		})
		Context("ソースファイルをコマンドリストに変換する関数", func() {
			It("スタックに１をプッシュするコマンドが作成されること", func() {
				data = []byte{'P', 'u', 's', 'h', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommandWithParam("stack", "push", 1))
			})
			It("スタックをコピーするコマンドが作成されること", func() {
				data = []byte{'C', 'o', 'p', 'y', ' ', '\n', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("stack", "copy"))
			})
			It("スタックを入れ替えるコマンドが作成されること", func() {
				data = []byte{'S', 'w', 'a', 'p', ' ', '\n', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("stack", "swap"))
			})
			It("スタックを削除するコマンドが作成されること", func() {
				data = []byte{'R', 'e', 'm', 'o', 'v', 'e', ' ', '\n', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("stack", "remove"))
			})
			It("定義されていない命令が指定されたときにundefinedの命令が作成されること", func() {
				data = []byte{'u', 'n', 'k', 'n', 'o', 'w', 'n', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
			It("ラベルを定義するコマンドが作成されること", func() {
				data = []byte{'L', 'a', 'b', 'l', '\n', ' ', ' ', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("label", "1001"))
			})
			It("ラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'C', 'a', 'l', 'l', '\n', ' ', '\t', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("call", "1001"))
			})
			It("ラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'G', 'o', 't', 'o', '\n', ' ', '\n', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("goto", "1001"))
			})
			It("スタックの値が０のときにラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'=', '=', '0', 'G', 'o', 't', 'o', '\n', '\t', ' ', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("if stack==0 then goto", "1001"))
			})
			It("スタックの値が０未満のときにラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'<', '0', 'G', 'o', 't', 'o', '\n', '\t', '\t', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("if stack<0 then goto", "1001"))
			})
			It("呼び出し元に戻るコマンドが作成されること", func() {
				data = []byte{'R', 'e', 't', 'u', 'r', 'n', '\n', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("return"))
			})
			It("プログラムを終了するコマンドが作成されること", func() {
				data = []byte{'E', 'x', 'i', 't', '\n', '\n', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("exit"))
			})
			It("解析できないパターンができたときにエラーが作成されること", func() {
				data = []byte{'u', 'n', 'k', 'o', 'w', 'n', '\n', '\n', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
			It("足し算する命令が作成されること", func() {
				data = []byte{'a', 'd', 'd', '\t', ' ', ' ', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("add"))
			})
			It("引き算する命令が作成されること", func() {
				data = []byte{'s', 'u', 'b', '\t', ' ', ' ', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("sub"))
			})
			It("掛け算する命令が作成されること", func() {
				data = []byte{'m', 'u', 'l', '\t', ' ', ' ', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("mul"))
			})
			It("割り算する命令が作成されること", func() {
				data = []byte{'d', 'i', 'v', '\t', ' ', '\t', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("div"))
			})
			It("余りを求める命令が作成されること", func() {
				data = []byte{'m', 'o', 'd', '\t', ' ', '\t', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("mod"))
			})
			It("解析できないパターンができたときにエラーが作成されること", func() {
				data = []byte{'u', 'n', 'k', 'o', 'w', 'n', '\t', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
			It("ヒープエリアに値をプッシュする命令が作成されること", func() {
				data = []byte{'h', 'e', 'a', 'p', '\t', 'p', 'u', 's', 'h', '\t', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("heap", "push"))
			})
			It("ヒープエリアから値をポップする命令が作成されること", func() {
				data = []byte{'h', 'e', 'a', 'p', '\t', 'p', 'o', 'p', '\t', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("heap", "pop"))
			})
			It("解析できないパターンができたときにエラーが作成されること", func() {
				data = []byte{'u', 'n', 'k', 'o', 'w', 'n', '\t', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
			It("スタックの内容を文字として標準出力する命令が作成されること", func() {
				data = []byte{'p', 'u', 't', 'c', '\t', '\n', ' ', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("putc"))
			})
			It("スタックの内容を数字として標準出力する命令が作成されること", func() {
				data = []byte{'p', 'u', 't', 'n', '\t', '\n', ' ', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("putn"))
			})
			It("標準入力の値を文字としてスタックに格納する命令が作成されること", func() {
				data = []byte{'g', 'e', 't', 'c', '\t', '\n', '\t', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("getc"))
			})
			It("標準入力の値を数値としてスタックに格納する命令が作成されること", func() {
				data = []byte{'g', 'e', 't', 'n', '\t', '\n', '\t', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("getn"))
			})
		})
	})
}

func current_dir() string {
	_, fpath, _, _ := runtime.Caller(0)
	return path.Dir(fpath)
}
<commit_msg>解析できないパターンがきたときにエラーが発生することを確認<commit_after>package wspacego

import (
	. "github.com/r7kamura/gospel"
	"path"
	"runtime"
	"testing"
)

func TestInterpretor(t *testing.T) {
	Describe(t, "インタープリターのテスト", func() {
		data := []byte{'A', ' ', 'B', '\t', '\r', '\n'}
		Context("インスタンス生成", func() {
			It("インスタンスが生成できること", func() {
				actual := NewInterpreter(data)
				Expect(actual).To(Exist)
				Expect(actual.origin).To(Equal, data)
			})
		})
		Context("不要な文字を排除する関数", func() {
			It("不要なデータ以外排除されていること", func() {
				sut := NewInterpreter(data)
				sut.filter()
				Expect(sut.source).To(Equal, []byte{' ', '\t', '\n'})
			})
			It("不要なデータ以外排除されていること（改行を増やす）", func() {
				data = append(data, '\n')
				sut := NewInterpreter(data)
				sut.filter()
				Expect(sut.source).To(Equal, []byte{' ', '\t', '\n', '\n'})
			})
		})
		Context("ソースファイルをコマンドリストに変換する関数", func() {
			It("スタックに１をプッシュするコマンドが作成されること", func() {
				data = []byte{'P', 'u', 's', 'h', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommandWithParam("stack", "push", 1))
			})
			It("スタックをコピーするコマンドが作成されること", func() {
				data = []byte{'C', 'o', 'p', 'y', ' ', '\n', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("stack", "copy"))
			})
			It("スタックを入れ替えるコマンドが作成されること", func() {
				data = []byte{'S', 'w', 'a', 'p', ' ', '\n', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("stack", "swap"))
			})
			It("スタックを削除するコマンドが作成されること", func() {
				data = []byte{'R', 'e', 'm', 'o', 'v', 'e', ' ', '\n', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("stack", "remove"))
			})
			It("定義されていない命令が指定されたときにundefinedの命令が作成されること", func() {
				data = []byte{'u', 'n', 'k', 'n', 'o', 'w', 'n', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
			It("ラベルを定義するコマンドが作成されること", func() {
				data = []byte{'L', 'a', 'b', 'l', '\n', ' ', ' ', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("label", "1001"))
			})
			It("ラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'C', 'a', 'l', 'l', '\n', ' ', '\t', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("call", "1001"))
			})
			It("ラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'G', 'o', 't', 'o', '\n', ' ', '\n', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("goto", "1001"))
			})
			It("スタックの値が０のときにラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'=', '=', '0', 'G', 'o', 't', 'o', '\n', '\t', ' ', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("if stack==0 then goto", "1001"))
			})
			It("スタックの値が０未満のときにラベルを呼び出すコマンドが作成されること", func() {
				data = []byte{'<', '0', 'G', 'o', 't', 'o', '\n', '\t', '\t', '\t', ' ', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("if stack<0 then goto", "1001"))
			})
			It("呼び出し元に戻るコマンドが作成されること", func() {
				data = []byte{'R', 'e', 't', 'u', 'r', 'n', '\n', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("return"))
			})
			It("プログラムを終了するコマンドが作成されること", func() {
				data = []byte{'E', 'x', 'i', 't', '\n', '\n', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("exit"))
			})
			It("解析できないパターンができたときにエラーが作成されること", func() {
				data = []byte{'u', 'n', 'k', 'o', 'w', 'n', '\n', '\n', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
			It("足し算する命令が作成されること", func() {
				data = []byte{'a', 'd', 'd', '\t', ' ', ' ', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("add"))
			})
			It("引き算する命令が作成されること", func() {
				data = []byte{'s', 'u', 'b', '\t', ' ', ' ', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("sub"))
			})
			It("掛け算する命令が作成されること", func() {
				data = []byte{'m', 'u', 'l', '\t', ' ', ' ', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("mul"))
			})
			It("割り算する命令が作成されること", func() {
				data = []byte{'d', 'i', 'v', '\t', ' ', '\t', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("div"))
			})
			It("余りを求める命令が作成されること", func() {
				data = []byte{'m', 'o', 'd', '\t', ' ', '\t', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("mod"))
			})
			It("解析できないパターンができたときにエラーが作成されること", func() {
				data = []byte{'u', 'n', 'k', 'o', 'w', 'n', '\t', ' ', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
			It("ヒープエリアに値をプッシュする命令が作成されること", func() {
				data = []byte{'h', 'e', 'a', 'p', '\t', 'p', 'u', 's', 'h', '\t', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("heap", "push"))
			})
			It("ヒープエリアから値をポップする命令が作成されること", func() {
				data = []byte{'h', 'e', 'a', 'p', '\t', 'p', 'o', 'p', '\t', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewSubCommand("heap", "pop"))
			})
			It("解析できないパターンができたときにエラーが作成されること", func() {
				data = []byte{'u', 'n', 'k', 'o', 'w', 'n', '\t', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
			It("スタックの内容を文字として標準出力する命令が作成されること", func() {
				data = []byte{'p', 'u', 't', 'c', '\t', '\n', ' ', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("putc"))
			})
			It("スタックの内容を数字として標準出力する命令が作成されること", func() {
				data = []byte{'p', 'u', 't', 'n', '\t', '\n', ' ', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("putn"))
			})
			It("標準入力の値を文字としてスタックに格納する命令が作成されること", func() {
				data = []byte{'g', 'e', 't', 'c', '\t', '\n', '\t', ' '}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("getc"))
			})
			It("標準入力の値を数値としてスタックに格納する命令が作成されること", func() {
				data = []byte{'g', 'e', 't', 'n', '\t', '\n', '\t', '\t'}
				sut := NewInterpreter(data)
				sut.filter()
				sut.parseCommands()
				Expect(sut.commands).To(Exist)
				Expect(sut.commands.Len()).To(Equal, 1)
				Expect(sut.commands.Get(1)).To(Equal, NewCommand("getn"))
			})
			It("解析できないパターンができたときにエラーが作成されること", func() {
				data = []byte{'u', 'n', 'k', 'o', 'w', 'n', '\t', '\n', '\t', '\n'}
				sut := NewInterpreter(data)
				sut.filter()
				err := sut.parseCommands()
				Expect(sut.commands).To(NotExist)
				Expect(err).To(Exist)
			})
		})
	})
}

func current_dir() string {
	_, fpath, _, _ := runtime.Caller(0)
	return path.Dir(fpath)
}
<|endoftext|>


<commit_before>package ircstats

type MaxWeek struct {
	Week  int64
	Lines int64
}

type MaxDay struct {
	Day   string
	Lines int64
}

type MaxHour struct {
	Hour  int64
	Lines int64
}

type Averages struct {
	Hour    float64 // Average lines by Hour (24 hours)
	Day     float64 // Average lines by day (365 days)
	Week    float64 // Average lines by week (week 1 - week 52)
	WeekDay float64 // Average lines by week day (monday - sunday)
}

//
// Channel Statistics
//
type Channel struct {
	Name              string          // Channel Name
	ActiveUsers       map[string]User // Active users in past 30 days
	UserCount         int64           // Total Number of users in Channel
	LineCount         int64           // Total Number of lines in Channel
	WordCount         int64           // Total Word count for Channel
	MaxDay            MaxDay          // Calculated Max Day
	MaxHour           MaxHour         // Calculated Max Hour
	MaxWeek           MaxWeek         // Calculated Max Week
	Averages          Averages        // Calculated Averages
	HoursAndDaysStats                 // Inherited Hour And Days methods
	Seen                              // First & Last Seen
}

// @todo add function for calculating max day

// @todo add function for calculating max hour

// @todo add function for calculating max week

// @todo add function for calculating averages

// @todo add function for calculating active users
<commit_msg>Removed fluff comments<commit_after>package ircstats

type MaxWeek struct {
	Week  int64
	Lines int64
}

type MaxDay struct {
	Day   string
	Lines int64
}

type MaxHour struct {
	Hour  int64
	Lines int64
}

type Averages struct {
	Hour    float64 // Average lines by Hour (24 hours)
	Day     float64 // Average lines by day (365 days)
	Week    float64 // Average lines by week (week 1 - week 52)
	WeekDay float64 // Average lines by week day (monday - sunday)
}

//
// Channel Statistics
//
type Channel struct {
	Name              string          // Channel Name
	ActiveUsers       map[string]User // Active users in past 30 days
	UserCount         int64           // Total Number of users in Channel
	LineCount         int64           // Total Number of lines in Channel
	WordCount         int64           // Total Word count for Channel
	MaxDay            MaxDay          // Calculated Max Day
	MaxHour           MaxHour         // Calculated Max Hour
	MaxWeek           MaxWeek         // Calculated Max Week
	Averages          Averages        // Calculated Averages
	HoursAndDaysStats                 // Inherited Hour And Days methods
	Seen                              // First & Last Seen
}
<|endoftext|>


<commit_before>package main

import (
  "fmt"
  "runtime"
  "time"
  "flag"

  "github.com/jmhodges/levigo"

  lns "github.com/abhishekkr/levigoNS"
  abkleveldb "github.com/abhishekkr/levigoNS/leveldb"
)

var (
  dbpath = flag.String("db", "/tmp/LevigoNS00", "the path to your db")
)

func EverySecondOfHour(hour int, check string, db *levigo.DB) {
  for sec := 0; sec < 3600; sec++{
    nukey := fmt.Sprintf("127.0.0.1:%s:2013:10:26:%d:%d",
                        check, hour, sec)
    val := "up"
    if sec%1000 == 0 {
      val = "down"
    }
    lns.PushNS(nukey, val, db)
  }
  fmt.Printf("Hour %s done. Enter 'yes' anytime to end Push action.", hour)
}

func WriteMap(db *levigo.DB){
  for hour := 0; hour < 24; hour++ {
    go EverySecondOfHour(hour, "status", db)
  }
  for {
    for {
      var quit string
      fmt.Scanf("%s", &quit)
      if quit == "y" || quit == "yes" {
        return
      }
    }
    time.Sleep(10 * time.Second)
  }
}

func ReadMap(key string, db *levigo.DB){
  var hmap map[string]string
  hmap = make(map[string]string)
  hmap = lns.ReadNS(key, db)
  fmt.Println("Total Child Keys found:", len(hmap))
  for k,v := range hmap {
    fmt.Printf("%s => %s\n", k, v)
  }
}

func main(){
  start_time := time.Now()
  runtime.GOMAXPROCS(runtime.NumCPU())
  var db *levigo.DB
  fmt.Println("Your DB is referenced at", *dbpath)
  create_start_time := time.Now()
  db = abkleveldb.CreateDB(*dbpath)
  WriteMap(db)
  read_start_time := time.Now()
  ReadMap("127.0.0.1:status:2013:10:26:12", db)
  fmt.Printf("\n\nStatistics:\n\tStarted at: %q\n", start_time)
  fmt.Printf("\tCreating DB: %q\n", create_start_time)
  fmt.Printf("\tReading DB: %q\n\tRead For an Hour: %q\n", read_start_time, time.Now())
}
<commit_msg>example updated with ReadNSRecursive<commit_after>package main

import (
  "fmt"
  "runtime"
  "time"
  "flag"

  "github.com/jmhodges/levigo"

  abklevigoNS "github.com/abhishekkr/levigoNS"
  abkleveldb "github.com/abhishekkr/levigoNS/leveldb"
)

var (
  dbpath = flag.String("db", "/tmp/LevigoNS00", "the path to your db")
)

func EverySecondOfHour(hour int, check string, db *levigo.DB) {
  for sec := 0; sec < 3600; sec++{
    nukey := fmt.Sprintf("127.0.0.1:%s:2013:10:26:%d:%d",
                        check, hour, sec)
    if sec%500 != 0 { continue }
    val := "up"
    if sec%1000 == 0 {
      val = "down"
    }
    abklevigoNS.PushNS(nukey, val, db)
  }
  fmt.Printf("Hour %d done. Enter 'yes' anytime to end Push action.\n", hour)
}

func WriteMap(db *levigo.DB){
  for hour := 0; hour < 24; hour++ {
    go EverySecondOfHour(hour, "status", db)
  }
  for {
    for {
      var quit string
      fmt.Scanf("%s", &quit)
      if quit == "y" || quit == "yes" {
        return
      }
    }
    time.Sleep(10 * time.Second)
  }
}

func ReadMap(key string, db *levigo.DB){
  var hmap map[string]string
  hmap = make(map[string]string)
  hmap = abklevigoNS.ReadNS(key, db)
  fmt.Println("Total Child Keys found:", len(hmap))
  for k,v := range hmap {
    fmt.Printf("%s => %s\n", k, v)
  }
}

func PrintMapRecursive(m abklevigoNS.HashMap){
  for k,v := range m {
    fmt.Println("val for key:", k, v)
  }
}

func main(){
  start_time := time.Now()
  runtime.GOMAXPROCS(runtime.NumCPU())
  var db *levigo.DB
  fmt.Println("Your DB is referenced at", *dbpath)
  create_start_time := time.Now()
  db = abkleveldb.CreateDB(*dbpath)
  WriteMap(db)
  fmt.Println("Writing is over.")
  ReadMap("127.0.0.1:status:2013:10:26:12", db)
  result := abklevigoNS.ReadNSRecursive("127.0.0.1:status", db)
  read_start_time := time.Now()
  PrintMapRecursive( result )
  ReadMap("127.0.0.1:status:2013:10:26", db)
  fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
  fmt.Printf("\n\nStatistics:\n\tStarted at: %q\n", start_time)
  fmt.Printf("\tCreating DB: %q\n", create_start_time)
  fmt.Printf("\tReading DB: %q\n\tRead For an Hour: %q\n", read_start_time, time.Now())
  fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
  fmt.Println(len(result))
}
<|endoftext|>


<commit_before>package styx

import (
	"os"
	"path"

	"golang.org/x/net/context"

	"aqwari.net/net/styx/internal/styxfile"
	"aqwari.net/net/styx/internal/sys"
	"aqwari.net/net/styx/styxproto"
)

// A Request is a request by a client to perform an operation
// on a file or set of files. Types of requests may range from
// checking if a file exists (Twalk) to opening a file (Topen)
// to changing a file's name (Twstat).
type Request interface {
	// The context.Context interface is used to implement cancellation and
	// request timeouts. If an operation is going to take a long time to
	// complete, you can allow for the client to cancel the request by receiving
	// on the channel returned by Done().
	context.Context

	// If a request is invalid, not allowed, or cannot be completed properly
	// for some other reason, its Rerror method should be used to respond
	// to it.
	Rerror(format string, args ...interface{})

	// Path returns the Path of the file being operated on.
	Path() string

	// For the programmer's convenience, each request type has a default
	// response. Programmers can choose to ignore requests of a given
	// type and have the styx package send default responses to them.
	// In most cases, the default response is to send an error that the user
	// has insufficient permissions or the file in question does not exist.
	defaultResponse()
	handled() bool
}

// common fields among all requests. Some may be nil for
// certain requests.
type reqInfo struct {
	context.Context
	tag     uint16
	fid     uint32
	session *Session
	msg     styxproto.Msg
	path    string

	// used to handle default responses
	sent bool
}

func (info reqInfo) handled() bool {
	return info.sent
}

// Path returns the absolute path of the file being operated on.
func (info reqInfo) Path() string {
	return info.path
}

// Rerror sends an error to the client.
func (info reqInfo) Rerror(format string, args ...interface{}) {
	info.sent = true
	info.session.conn.clearTag(info.tag)
	info.session.conn.Rerror(info.tag, format, args...)
}

func newReqInfo(cx context.Context, s *Session, msg fcall, filepath string) reqInfo {
	return reqInfo{
		session: s,
		tag:     msg.Tag(),
		fid:     msg.Fid(),
		Context: cx,
		msg:     msg,
		path:    filepath,
	}
}

// A Topen message is sent when a client wants to open a file for I/O
// Use the Ropen method to provide the opened file.
//
// The default response to a Topen message to send an Rerror message
// saying "permssion denied".
type Topen struct {
	// The mode to open the file with. One of the flag constants
	// in the os package, such as O_RDWR, O_APPEND etc.
	Flag int
	reqInfo
}

// The Ropen method signals to the client that a file has succesfully
// been opened and is ready for I/O. After Ropen returns, future reads
// and writes to the opened file handle will pass through rwc.
//
// The value rwc must implement some of the interfaces in the io package
// for reading and writing. If the type implements io.Seeker or io.ReaderAt
// and io.WriterAt, clients may read or write at arbitrary offsets within
// the file. Types that only implement Read or Write operations will return
// errors on writes and reads, respectively.
//
// If a file does not implement any of the Read or Write interfaces in
// the io package, A generic error is returned to the client, and a message
// will be written to the server's ErrorLog.
func (t Topen) Ropen(rwc interface{}, mode os.FileMode) {
	t.sent = true
	var (
		file file
		f    styxfile.Interface
		err  error
	)
	if dir, ok := rwc.(Directory); ok && mode.IsDir() {
		f = styxfile.NewDir(dir, t.Path(), t.session.conn.qidpool)
	} else {
		f, err = styxfile.New(rwc)
	}

	if err != nil {
		t.session.conn.srv.logf("%s open %s failed: %s", t.path, err)

		// Don't want to expose too many implementation details
		// to clients.
		t.Rerror("open failed")
		return
	}
	t.session.files.Update(t.fid, &file, func() {
		file.rwc = f
	})
	qidtype := styxfile.QidType(styxfile.Mode9P(mode))
	qid := t.session.conn.qid(t.Path(), qidtype)
	t.session.conn.clearTag(t.tag)
	t.session.conn.Ropen(t.tag, qid, 0)
}

func (t Topen) defaultResponse() {
	t.Rerror("permission denied")
}

// A Tstat message is sent when a client wants metadata about a file.
// A client should have read access to the file's containing directory.
// Call the Rstat method for a succesful request.
//
// The default response for a Tstat message is an Rerror message
// saying "permission denied".
type Tstat struct {
	reqInfo
}

// Rstat responds to a succesful Tstat request. The styx package will
// translate the os.FileInfo value into the appropriate 9P structure. Rstat
// will attempt to resolve the names of the file's owner and group. If
// that cannot be done, an empty string is sent.
func (t Tstat) Rstat(info os.FileInfo) {
	t.sent = true
	buf := make([]byte, styxproto.MaxStatLen)
	uid, gid, muid := sys.FileOwner(info)
	name := info.Name()
	if name == "/" {
		name = "."
	}
	stat, _, err := styxproto.NewStat(buf, name, uid, gid, muid)
	if err != nil {
		// should never happen
		panic(err)
	}
	mode := styxfile.Mode9P(info.Mode())
	stat.SetLength(info.Size())
	stat.SetMode(mode)
	stat.SetAtime(uint32(info.ModTime().Unix())) // TODO: get atime
	stat.SetMtime(uint32(info.ModTime().Unix()))
	stat.SetQid(t.session.conn.qid(t.Path(), styxfile.QidType(mode)))
	t.session.conn.clearTag(t.tag)
	t.session.conn.Rstat(t.tag, stat)
}

func (t Tstat) defaultResponse() {
	t.Rerror("permission denied")
}

// A Tcreate message is sent when a client wants to create a new file
// and open it with the provided Mode. The Path method of a Tcreate
// message returns the absolute path of the containing directory. A user
// must have write permissions in the directory to create a file.
//
// The default response to a Tcreate message is an Rerror message
// saying "permission denied".
type Tcreate struct {
	Name string      // name of the file to create
	Perm os.FileMode // permissions and file type to create
	Flag int         // flags to open the new file with
	reqInfo
}

// NewPath joins the path for the Tcreate's containing directory
// with its Name field, returning the absolute path to the new file.
func (t Tcreate) NewPath() string {
	return path.Join(t.Path(), t.Name)
}

// Path returns the absolute path to the containing directory of the
// new file.
func (t Tcreate) Path() string {
	return t.reqInfo.Path() // overrode this method for the godoc comments
}

// Rcreate is used to respond to a succesful create request. With 9P, creating
// a file also opens the file for I/O. Once Rcreate returns, future read
// and write requests to the file handle will pass through rwc. The value
// rwc must meet the same criteria listed for the Ropen method of a Topen
// request.
func (t Tcreate) Rcreate(rwc interface{}) {
	t.sent = true
	var (
		f   styxfile.Interface
		err error
	)
	if dir, ok := rwc.(Directory); t.Perm.IsDir() && ok {
		f = styxfile.NewDir(dir, path.Join(t.Path(), t.Name), t.session.conn.qidpool)
	} else {
		f, err = styxfile.New(rwc)
	}
	if err != nil {
		t.session.conn.srv.logf("create %s failed: %s", t.Name, err)
		t.Rerror("create failed")
		return
	}
	file := file{name: path.Join(t.Path(), t.Name), rwc: f}

	// fid for parent directory is now the fid for the new file,
	// so there is no increase in references to this session.
	t.session.files.Put(t.fid, file)

	qtype := styxfile.QidType(styxfile.Mode9P(t.Perm))
	qid := t.session.conn.qid(file.name, qtype)
	t.session.conn.clearTag(t.tag)
	t.session.conn.Rcreate(t.tag, qid, 0)
}

func (t Tcreate) defaultResponse() {
	t.Rerror("permission denied")
}

// A Tremove message is sent when a client wants to delete a file
// from the server. The Rremove method should be called once the
// file has been succesfully deleted.
//
// The default response to a Tremove message is an Rerror message
// saying "permission denied".
type Tremove struct {
	reqInfo
}

// Rremove signals to the client that a file has been succesfully
// removed. The file handle for the file is no longer valid, and may be
// re-used for other files. Whether or not any other file handles associated
// with the file continue to be usable for I/O is implementation-defined;
// many Unix file systems allow a process to continue writing to a file that
// has been "unlinked", so long as the process has an open file descriptor.
func (t Tremove) Rremove() {
	t.sent = true
	t.session.conn.sessionFid.Del(t.fid)
	t.session.files.Del(t.fid)

	// NOTE(droyo): This is not entirely correct; if the server wants
	// to implement unix-like semantics (the file hangs around as
	// long as there's 1 descriptor for it), we should not delete the
	// qid until *all* references to it are removed. We'll need to implement
	// reference counting for that :\
	t.session.conn.qidpool.Del(t.Path())

	t.session.conn.clearTag(t.tag)
	t.session.conn.Rremove(t.tag)
	if !t.session.DecRef() {
		t.session.close()
	}
}

func (t Tremove) defaultResponse() {
	t.Rerror("permission denied")
}
<commit_msg>Allow Rremove to accept an error value<commit_after>package styx

import (
	"os"
	"path"

	"golang.org/x/net/context"

	"aqwari.net/net/styx/internal/styxfile"
	"aqwari.net/net/styx/internal/sys"
	"aqwari.net/net/styx/styxproto"
)

// A Request is a request by a client to perform an operation
// on a file or set of files. Types of requests may range from
// checking if a file exists (Twalk) to opening a file (Topen)
// to changing a file's name (Twstat).
type Request interface {
	// The context.Context interface is used to implement cancellation and
	// request timeouts. If an operation is going to take a long time to
	// complete, you can allow for the client to cancel the request by receiving
	// on the channel returned by Done().
	context.Context

	// If a request is invalid, not allowed, or cannot be completed properly
	// for some other reason, its Rerror method should be used to respond
	// to it.
	Rerror(format string, args ...interface{})

	// Path returns the Path of the file being operated on.
	Path() string

	// For the programmer's convenience, each request type has a default
	// response. Programmers can choose to ignore requests of a given
	// type and have the styx package send default responses to them.
	// In most cases, the default response is to send an error that the user
	// has insufficient permissions or the file in question does not exist.
	defaultResponse()
	handled() bool
}

// common fields among all requests. Some may be nil for
// certain requests.
type reqInfo struct {
	context.Context
	tag     uint16
	fid     uint32
	session *Session
	msg     styxproto.Msg
	path    string

	// used to handle default responses
	sent bool
}

func (info reqInfo) handled() bool {
	return info.sent
}

// Path returns the absolute path of the file being operated on.
func (info reqInfo) Path() string {
	return info.path
}

// Rerror sends an error to the client.
func (info reqInfo) Rerror(format string, args ...interface{}) {
	info.sent = true
	info.session.conn.clearTag(info.tag)
	info.session.conn.Rerror(info.tag, format, args...)
}

func newReqInfo(cx context.Context, s *Session, msg fcall, filepath string) reqInfo {
	return reqInfo{
		session: s,
		tag:     msg.Tag(),
		fid:     msg.Fid(),
		Context: cx,
		msg:     msg,
		path:    filepath,
	}
}

// A Topen message is sent when a client wants to open a file for I/O
// Use the Ropen method to provide the opened file.
//
// The default response to a Topen message to send an Rerror message
// saying "permssion denied".
type Topen struct {
	// The mode to open the file with. One of the flag constants
	// in the os package, such as O_RDWR, O_APPEND etc.
	Flag int
	reqInfo
}

// The Ropen method signals to the client that a file has succesfully
// been opened and is ready for I/O. After Ropen returns, future reads
// and writes to the opened file handle will pass through rwc.
//
// The value rwc must implement some of the interfaces in the io package
// for reading and writing. If the type implements io.Seeker or io.ReaderAt
// and io.WriterAt, clients may read or write at arbitrary offsets within
// the file. Types that only implement Read or Write operations will return
// errors on writes and reads, respectively.
//
// If a file does not implement any of the Read or Write interfaces in
// the io package, A generic error is returned to the client, and a message
// will be written to the server's ErrorLog.
func (t Topen) Ropen(rwc interface{}, mode os.FileMode) {
	t.sent = true
	var (
		file file
		f    styxfile.Interface
		err  error
	)
	if dir, ok := rwc.(Directory); ok && mode.IsDir() {
		f = styxfile.NewDir(dir, t.Path(), t.session.conn.qidpool)
	} else {
		f, err = styxfile.New(rwc)
	}

	if err != nil {
		t.session.conn.srv.logf("%s open %s failed: %s", t.path, err)

		// Don't want to expose too many implementation details
		// to clients.
		t.Rerror("open failed")
		return
	}
	t.session.files.Update(t.fid, &file, func() {
		file.rwc = f
	})
	qidtype := styxfile.QidType(styxfile.Mode9P(mode))
	qid := t.session.conn.qid(t.Path(), qidtype)
	t.session.conn.clearTag(t.tag)
	t.session.conn.Ropen(t.tag, qid, 0)
}

func (t Topen) defaultResponse() {
	t.Rerror("permission denied")
}

// A Tstat message is sent when a client wants metadata about a file.
// A client should have read access to the file's containing directory.
// Call the Rstat method for a succesful request.
//
// The default response for a Tstat message is an Rerror message
// saying "permission denied".
type Tstat struct {
	reqInfo
}

// Rstat responds to a succesful Tstat request. The styx package will
// translate the os.FileInfo value into the appropriate 9P structure. Rstat
// will attempt to resolve the names of the file's owner and group. If
// that cannot be done, an empty string is sent.
func (t Tstat) Rstat(info os.FileInfo) {
	t.sent = true
	buf := make([]byte, styxproto.MaxStatLen)
	uid, gid, muid := sys.FileOwner(info)
	name := info.Name()
	if name == "/" {
		name = "."
	}
	stat, _, err := styxproto.NewStat(buf, name, uid, gid, muid)
	if err != nil {
		// should never happen
		panic(err)
	}
	mode := styxfile.Mode9P(info.Mode())
	stat.SetLength(info.Size())
	stat.SetMode(mode)
	stat.SetAtime(uint32(info.ModTime().Unix())) // TODO: get atime
	stat.SetMtime(uint32(info.ModTime().Unix()))
	stat.SetQid(t.session.conn.qid(t.Path(), styxfile.QidType(mode)))
	t.session.conn.clearTag(t.tag)
	t.session.conn.Rstat(t.tag, stat)
}

func (t Tstat) defaultResponse() {
	t.Rerror("permission denied")
}

// A Tcreate message is sent when a client wants to create a new file
// and open it with the provided Mode. The Path method of a Tcreate
// message returns the absolute path of the containing directory. A user
// must have write permissions in the directory to create a file.
//
// The default response to a Tcreate message is an Rerror message
// saying "permission denied".
type Tcreate struct {
	Name string      // name of the file to create
	Perm os.FileMode // permissions and file type to create
	Flag int         // flags to open the new file with
	reqInfo
}

// NewPath joins the path for the Tcreate's containing directory
// with its Name field, returning the absolute path to the new file.
func (t Tcreate) NewPath() string {
	return path.Join(t.Path(), t.Name)
}

// Path returns the absolute path to the containing directory of the
// new file.
func (t Tcreate) Path() string {
	return t.reqInfo.Path() // overrode this method for the godoc comments
}

// Rcreate is used to respond to a succesful create request. With 9P, creating
// a file also opens the file for I/O. Once Rcreate returns, future read
// and write requests to the file handle will pass through rwc. The value
// rwc must meet the same criteria listed for the Ropen method of a Topen
// request.
func (t Tcreate) Rcreate(rwc interface{}) {
	t.sent = true
	var (
		f   styxfile.Interface
		err error
	)
	if dir, ok := rwc.(Directory); t.Perm.IsDir() && ok {
		f = styxfile.NewDir(dir, path.Join(t.Path(), t.Name), t.session.conn.qidpool)
	} else {
		f, err = styxfile.New(rwc)
	}
	if err != nil {
		t.session.conn.srv.logf("create %s failed: %s", t.Name, err)
		t.Rerror("create failed")
		return
	}
	file := file{name: path.Join(t.Path(), t.Name), rwc: f}

	// fid for parent directory is now the fid for the new file,
	// so there is no increase in references to this session.
	t.session.files.Put(t.fid, file)

	qtype := styxfile.QidType(styxfile.Mode9P(t.Perm))
	qid := t.session.conn.qid(file.name, qtype)
	t.session.conn.clearTag(t.tag)
	t.session.conn.Rcreate(t.tag, qid, 0)
}

func (t Tcreate) defaultResponse() {
	t.Rerror("permission denied")
}

// A Tremove message is sent when a client wants to delete a file
// from the server. The Rremove method should be called once the
// file has been succesfully deleted.
//
// The default response to a Tremove message is an Rerror message
// saying "permission denied".
type Tremove struct {
	reqInfo
}

// Rremove signals to the client that a file has been succesfully
// removed. The file handle for the file is no longer valid, and may be
// re-used for other files. Whether or not any other file handles associated
// with the file continue to be usable for I/O is implementation-defined;
// many Unix file systems allow a process to continue writing to a file that
// has been "unlinked", so long as the process has an open file descriptor.
//
// If err is non-nil, an Rerror message is sent to the client. Regardless, the
// file handle is no longer valid.
func (t Tremove) Rremove(err error) {
	t.sent = true
	t.session.conn.sessionFid.Del(t.fid)
	t.session.files.Del(t.fid)

	t.session.conn.clearTag(t.tag)

	// NOTE(droyo): This is not entirely correct; if the server wants
	// to implement unix-like semantics (the file hangs around as
	// long as there's 1 descriptor for it), we should not delete the
	// qid until *all* references to it are removed. We'll need to implement
	// reference counting for that :\
	if err != nil {
		t.session.conn.Rerror(t.tag, "%s", err)
	} else {
		t.session.conn.qidpool.Del(t.Path())
		t.session.conn.Rremove(t.tag)
	}

	if !t.session.DecRef() {
		t.session.close()
	}
}

func (t Tremove) defaultResponse() {
	t.Rerror("permission denied")
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

import (
	"bytes"
	"compress/gzip"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"runtime"
	"strings"
)

// Elasticsearch-specific HTTP request
type Request http.Request

// NewRequest is a http.Request and adds features such as encoding the body.
func NewRequest(method, url string) (*Request, error) {
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("User-Agent", "elastic/"+Version+" ("+runtime.GOOS+"-"+runtime.GOARCH+")")
	req.Header.Add("Accept", "application/json")
	return (*Request)(req), nil
}

// SetBasicAuth wraps http.Request's SetBasicAuth.
func (r *Request) SetBasicAuth(username, password string) {
	((*http.Request)(r)).SetBasicAuth(username, password)
}

// SetBody encodes the body in the request. Optionally, it performs GZIP compression.
func (r *Request) SetBody(body interface{}, gzipCompress bool) error {
	switch b := body.(type) {
	case string:
		if gzipCompress {
			return r.setBodyGzip(body)
		} else {
			return r.setBodyString(b)
		}
	default:
		if gzipCompress {
			return r.setBodyGzip(body)
		} else {
			return r.setBodyJson(body)
		}
	}
}

// setBodyJson encodes the body as a struct to be marshaled via json.Marshal.
func (r *Request) setBodyJson(data interface{}) error {
	body, err := json.Marshal(data)
	if err != nil {
		return err
	}
	r.Header.Set("Content-Type", "application/json")
	r.setBodyReader(bytes.NewReader(body))
	return nil
}

// setBodyString encodes the body as a string.
func (r *Request) setBodyString(body string) error {
	return r.setBodyReader(strings.NewReader(body))
}

// setBodyGzip gzip's the body. It accepts both strings and structs as body.
// The latter will be encoded via json.Marshal.
func (r *Request) setBodyGzip(body interface{}) error {
	switch b := body.(type) {
	case string:
		buf := new(bytes.Buffer)
		w := gzip.NewWriter(buf)
		if _, err := w.Write([]byte(b)); err != nil {
			return err
		}
		r.Header.Add("Content-Encoding", "gzip")
		r.Header.Add("Vary", "Accept-Encoding")
		return r.setBodyReader(bytes.NewReader(buf.Bytes()))
	default:
		data, err := json.Marshal(b)
		if err != nil {
			return err
		}
		r.Header.Add("Content-Encoding", "gzip")
		r.Header.Add("Vary", "Accept-Encoding")
		r.Header.Set("Content-Type", "application/json")
		return r.setBodyReader(bytes.NewReader(data))
	}
}

// setBodyReader writes the body from an io.Reader.
func (r *Request) setBodyReader(body io.Reader) error {
	rc, ok := body.(io.ReadCloser)
	if !ok && body != nil {
		rc = ioutil.NopCloser(body)
	}
	r.Body = rc
	if body != nil {
		switch v := body.(type) {
		case *strings.Reader:
			r.ContentLength = int64(v.Len())
		case *bytes.Buffer:
			r.ContentLength = int64(v.Len())
		}
	}
	return nil
}
<commit_msg>wip: Close writer and compress marshaled data<commit_after>// Copyright 2012-2015 Oliver Eilhard. All rights reserved.
// Use of this source code is governed by a MIT-license.
// See http://olivere.mit-license.org/license.txt for details.

package elastic

import (
	"bytes"
	"compress/gzip"
	"encoding/json"
	"io"
	"io/ioutil"
	"net/http"
	"runtime"
	"strings"
)

// Elasticsearch-specific HTTP request
type Request http.Request

// NewRequest is a http.Request and adds features such as encoding the body.
func NewRequest(method, url string) (*Request, error) {
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		return nil, err
	}
	req.Header.Add("User-Agent", "elastic/"+Version+" ("+runtime.GOOS+"-"+runtime.GOARCH+")")
	req.Header.Add("Accept", "application/json")
	return (*Request)(req), nil
}

// SetBasicAuth wraps http.Request's SetBasicAuth.
func (r *Request) SetBasicAuth(username, password string) {
	((*http.Request)(r)).SetBasicAuth(username, password)
}

// SetBody encodes the body in the request. Optionally, it performs GZIP compression.
func (r *Request) SetBody(body interface{}, gzipCompress bool) error {
	switch b := body.(type) {
	case string:
		if gzipCompress {
			return r.setBodyGzip(b)
		} else {
			return r.setBodyString(b)
		}
	default:
		if gzipCompress {
			return r.setBodyGzip(body)
		} else {
			return r.setBodyJson(body)
		}
	}
}

// setBodyJson encodes the body as a struct to be marshaled via json.Marshal.
func (r *Request) setBodyJson(data interface{}) error {
	body, err := json.Marshal(data)
	if err != nil {
		return err
	}
	r.Header.Set("Content-Type", "application/json")
	r.setBodyReader(bytes.NewReader(body))
	return nil
}

// setBodyString encodes the body as a string.
func (r *Request) setBodyString(body string) error {
	return r.setBodyReader(strings.NewReader(body))
}

// setBodyGzip gzip's the body. It accepts both strings and structs as body.
// The latter will be encoded via json.Marshal.
func (r *Request) setBodyGzip(body interface{}) error {
	switch b := body.(type) {
	case string:
		buf := new(bytes.Buffer)
		w := gzip.NewWriter(buf)
		if _, err := w.Write([]byte(b)); err != nil {
			return err
		}
		if err := w.Close(); err != nil {
			return err
		}
		r.Header.Add("Content-Encoding", "gzip")
		r.Header.Add("Vary", "Accept-Encoding")
		return r.setBodyReader(bytes.NewReader(buf.Bytes()))
	default:
		data, err := json.Marshal(b)
		if err != nil {
			return err
		}
		buf := new(bytes.Buffer)
		w := gzip.NewWriter(buf)
		if _, err := w.Write(data); err != nil {
			return err
		}
		if err := w.Close(); err != nil {
			return err
		}
		r.Header.Add("Content-Encoding", "gzip")
		r.Header.Add("Vary", "Accept-Encoding")
		r.Header.Set("Content-Type", "application/json")
		return r.setBodyReader(bytes.NewReader(buf.Bytes()))
	}
}

// setBodyReader writes the body from an io.Reader.
func (r *Request) setBodyReader(body io.Reader) error {
	rc, ok := body.(io.ReadCloser)
	if !ok && body != nil {
		rc = ioutil.NopCloser(body)
	}
	r.Body = rc
	if body != nil {
		switch v := body.(type) {
		case *strings.Reader:
			r.ContentLength = int64(v.Len())
		case *bytes.Buffer:
			r.ContentLength = int64(v.Len())
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package rapi

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

// Request gathers all information about request
type Request struct {
	ID     int64  // storing record ID from URL
	Root   string // default JSON root key
	Action string
	params map[string]interface{}

	req *http.Request
	w   http.ResponseWriter
}

// Init initializing controller
func (r *Request) Init(w http.ResponseWriter, req *http.Request, root, prefix string) {
	r.w = w
	r.req = req
	r.Root = root

	urlParts := getParts(req.URL.Path, prefix)
	r.ID = urlParts.ID()
	r.Action = r.makeAction(urlParts)

	r.params = make(map[string]interface{})
}

func (r *Request) makeAction(urlParts parts) string {
	if urlParts.action != "" {
		return r.req.Method + capitalize(urlParts.action)
	}
	if r.ID > 0 {
		switch r.req.Method {
		case "GET":
			return "Show"
		case "POST", "PUT":
			return "Update"
		case "DELETE":
			return "Destroy"
		}
	}

	if urlParts.id != "" {
		return r.req.Method + capitalize(urlParts.id)
	}

	switch r.req.Method {
	case "GET":
		return "Index"
	case "POST":
		return "Create"
	}

	return "WrongAction"
}

// LoadJSONRequest extracting JSON request by key
// from request body into interface
func (r *Request) LoadJSONRequest(root string, v interface{}) {
	defer r.req.Body.Close()

	if root == "" {
		extractJSONPayload(r.req.Body, &v)
		return
	}

	var s []byte
	var body JSONData
	extractJSONPayload(r.req.Body, &body)
	s, _ = json.Marshal(body[root])
	json.Unmarshal(s, &v)
}

// QueryParam returns URL query param
func (r *Request) QueryParam(s string) string {
	return r.req.URL.Query().Get(s)
}

// SetParam set custom parameter for current request
func (r *Request) SetParam(k string, v interface{}) {
	r.params[k] = v
}

// Param returns custom parameter for current request
func (r *Request) Param(k string) interface{} {
	return r.params[k]
}

// Header returns request header
func (r *Request) Header(s string) string {
	return r.req.Header.Get(s)
}

// CurrentAction returns current controller action
func (r *Request) CurrentAction() string {
	return r.Action
}

// RenderJSON rendering JSON to client
func (r *Request) RenderJSON(code int, s JSONData) {
	if strings.Contains(r.req.Header.Get("Accept-Encoding"), "gzip") {
		RenderJSONgzip(r.w, code, s)
	} else {
		RenderJSON(r.w, code, s)
	}
}

// RenderJSONError rendering error to client in JSON format
func (r *Request) RenderJSONError(code int, s string) {
	r.RenderJSON(code, JSONData{"errors": JSONData{"message": []string{s}}})
}

// Render rendering string to client
func (r *Request) RenderString(code int, s string) {
	r.w.WriteHeader(code)
	r.w.Write([]byte(s))
}

// RenderError rendering error to client
func (r *Request) RenderError(code int, s string) {
	http.Error(r.w, s, code)
}

// LoadFile handling file uploads
func (r *Request) LoadFile(field, dir string) (string, error) {
	r.req.ParseMultipartForm(32 << 20)
	file, handler, err := r.req.FormFile(field)
	if err != nil {
		return "", err
	}
	defer file.Close()
	fmt.Fprintf(r.w, "%v", handler.Header)
	f, err := os.OpenFile(dir+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		return "", err
	}
	defer f.Close()
	io.Copy(f, file)
	return handler.Filename, nil
}

type parts struct {
	id, action string
}

func (p parts) ID() (i int64) {
	i, _ = strconv.ParseInt(p.id, 10, 64)
	return
}

func getParts(path, prefix string) parts {
	res := parts{}
	path = strings.TrimPrefix(path, prefix)
	path = strings.TrimSpace(path)
	path = strings.TrimPrefix(path, "/")
	path = strings.TrimSuffix(path, "/")
	parts := strings.Split(path, "/")

	l := len(parts)

	if l > 0 {
		res.id = parts[0]
		if l > 1 {
			res.action = parts[1]
		}
	}

	return res
}
<commit_msg>cleaning<commit_after>package rapi

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

// Request gathers all information about request
type Request struct {
	ID     int64  // storing record ID from URL
	Root   string // default JSON root key
	Action string
	params map[string]interface{}

	req *http.Request
	w   http.ResponseWriter
}

// Init initializing controller
func (r *Request) Init(w http.ResponseWriter, req *http.Request, root, prefix string) {
	r.w = w
	r.req = req
	r.Root = root

	urlParts := getParts(req.URL.Path, prefix)
	r.ID = urlParts.ID()
	r.Action = r.makeAction(urlParts)

	r.params = make(map[string]interface{})
}

func (r *Request) makeAction(urlParts parts) string {
	if urlParts.action != "" {
		return r.req.Method + capitalize(urlParts.action)
	}
	if r.ID > 0 {
		switch r.req.Method {
		case "GET":
			return "Show"
		case "POST", "PUT":
			return "Update"
		case "DELETE":
			return "Destroy"
		}
	}

	if urlParts.id != "" {
		return r.req.Method + capitalize(urlParts.id)
	}

	switch r.req.Method {
	case "GET":
		return "Index"
	case "POST":
		return "Create"
	}

	return "WrongAction"
}

// LoadJSONRequest extracting JSON request by key
// from request body into interface
func (r *Request) LoadJSONRequest(root string, v interface{}) {
	defer r.req.Body.Close()

	if root == "" {
		extractJSONPayload(r.req.Body, &v)
		return
	}

	var s []byte
	var body JSONData
	extractJSONPayload(r.req.Body, &body)
	s, _ = json.Marshal(body[root])
	json.Unmarshal(s, &v)
}

// QueryParam returns URL query param
func (r *Request) QueryParam(s string) string {
	return r.req.URL.Query().Get(s)
}

// SetParam set custom parameter for current request
func (r *Request) SetParam(k string, v interface{}) {
	r.params[k] = v
}

// Param returns custom parameter for current request
func (r *Request) Param(k string) interface{} {
	return r.params[k]
}

// Header returns request header
func (r *Request) Header(s string) string {
	return r.req.Header.Get(s)
}

// CurrentAction returns current controller action
func (r *Request) CurrentAction() string {
	return r.Action
}

// RenderJSON rendering JSON to client
func (r *Request) RenderJSON(code int, s JSONData) {
	if strings.Contains(r.req.Header.Get("Accept-Encoding"), "gzip") {
		RenderJSONgzip(r.w, code, s)
	} else {
		RenderJSON(r.w, code, s)
	}
}

// RenderJSONError rendering error to client in JSON format
func (r *Request) RenderJSONError(code int, s string) {
	r.RenderJSON(code, JSONData{"errors": JSONData{"message": []string{s}}})
}

// Render rendering string to client
func (r *Request) RenderString(code int, s string) {
	r.w.WriteHeader(code)
	r.w.Write([]byte(s))
}

// RenderError rendering error to client
func (r *Request) RenderError(code int, s string) {
	http.Error(r.w, s, code)
}

// LoadFile handling file uploads
func (r *Request) LoadFile(field, dir string) (string, error) {
	r.req.ParseMultipartForm(32 << 20)
	file, handler, err := r.req.FormFile(field)
	if err != nil {
		return "", err
	}
	defer file.Close()
	fmt.Fprintf(r.w, "%v", handler.Header)
	f, err := os.OpenFile(dir+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		return "", err
	}
	defer f.Close()
	io.Copy(f, file)
	return handler.Filename, nil
}

type parts struct {
	id, action string
}

func (p parts) ID() (i int64) {
	i, _ = strconv.ParseInt(p.id, 10, 64)
	return
}

func getParts(path, prefix string) parts {
	res := parts{}
	path = strings.TrimPrefix(path, prefix)
	path = strings.TrimPrefix(path, "/")
	path = strings.TrimSuffix(path, "/")
	parts := strings.Split(path, "/")

	l := len(parts)

	if l > 0 {
		res.id = parts[0]
		if l > 1 {
			res.action = parts[1]
		}
	}

	return res
}
<|endoftext|>


<commit_before>package restful

// Copyright 2013 Ernest Micklei. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.

import (
	"compress/zlib"
	"net/http"
)

var defaultRequestContentType string

// Request is a wrapper for a http Request that provides convenience methods
type Request struct {
	Request           *http.Request
	pathParameters    map[string]string
	attributes        map[string]interface{} // for storing request-scoped values
	selectedRoutePath string                 // root path + route path that matched the request, e.g. /meetings/{id}/attendees
	selectedRoute     *Route
}

func NewRequest(httpRequest *http.Request) *Request {
	return &Request{
		Request:        httpRequest,
		pathParameters: map[string]string{},
		attributes:     map[string]interface{}{},
	} // empty parameters, attributes
}

// If ContentType is missing or */* is given then fall back to this type, otherwise
// a "Unable to unmarshal content of type:" response is returned.
// Valid values are restful.MIME_JSON and restful.MIME_XML
// Example:
// 	restful.DefaultRequestContentType(restful.MIME_JSON)
func DefaultRequestContentType(mime string) {
	defaultRequestContentType = mime
}

// PathParameter accesses the Path parameter value by its name
func (r *Request) PathParameter(name string) string {
	return r.pathParameters[name]
}

// PathParameters accesses the Path parameter values
func (r *Request) PathParameters() map[string]string {
	return r.pathParameters
}

// QueryParameter returns the (first) Query parameter value by its name
func (r *Request) QueryParameter(name string) string {
	return r.Request.FormValue(name)
}

// QueryParameters returns the all the query parameters values by name
func (r *Request) QueryParameters(name string) []string {
	return r.Request.URL.Query()[name]
}

// BodyParameter parses the body of the request (once for typically a POST or a PUT) and returns the value of the given name or an error.
func (r *Request) BodyParameter(name string) (string, error) {
	err := r.Request.ParseForm()
	if err != nil {
		return "", err
	}
	return r.Request.PostFormValue(name), nil
}

// HeaderParameter returns the HTTP Header value of a Header name or empty if missing
func (r *Request) HeaderParameter(name string) string {
	return r.Request.Header.Get(name)
}

// ReadEntity checks the Accept header and reads the content into the entityPointer.
func (r *Request) ReadEntity(entityPointer interface{}) (err error) {
	contentType := r.Request.Header.Get(HEADER_ContentType)
	contentEncoding := r.Request.Header.Get(HEADER_ContentEncoding)

	// check if the request body needs decompression
	if ENCODING_GZIP == contentEncoding {
		gzipReader := currentCompressorProvider.AcquireGzipReader()
		defer currentCompressorProvider.ReleaseGzipReader(gzipReader)
		gzipReader.Reset(r.Request.Body)
		r.Request.Body = gzipReader
	} else if ENCODING_DEFLATE == contentEncoding {
		zlibReader, err := zlib.NewReader(r.Request.Body)
		if err != nil {
			return err
		}
		r.Request.Body = zlibReader
	}

	// lookup the EntityReader, use defaultRequestContentType if needed and provided
	entityReader, ok := entityAccessRegistry.accessorAt(contentType)
	if !ok {
		if len(defaultRequestContentType) != 0 {
			entityReader, ok = entityAccessRegistry.accessorAt(defaultRequestContentType)
		}
		if !ok {
			return NewError(http.StatusBadRequest, "Unable to unmarshal content of type:"+contentType)
		}
	}
	return entityReader.Read(r, entityPointer)
}

// SetAttribute adds or replaces the attribute with the given value.
func (r *Request) SetAttribute(name string, value interface{}) {
	r.attributes[name] = value
}

// Attribute returns the value associated to the given name. Returns nil if absent.
func (r Request) Attribute(name string) interface{} {
	return r.attributes[name]
}

// SelectedRoutePath root path + route path that matched the request, e.g. /meetings/{id}/attendees
func (r Request) SelectedRoutePath() string {
	return r.selectedRoute.Path
}

// SelectedRoute return the Route that selected by the container
func (r Request) SelectedRoute() RouteReader {
	return routeAccessor{route: r.selectedRoute}
}
<commit_msg>fix comment<commit_after>package restful

// Copyright 2013 Ernest Micklei. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.

import (
	"compress/zlib"
	"net/http"
)

var defaultRequestContentType string

// Request is a wrapper for a http Request that provides convenience methods
type Request struct {
	Request           *http.Request
	pathParameters    map[string]string
	attributes        map[string]interface{} // for storing request-scoped values
	selectedRoutePath string                 // root path + route path that matched the request, e.g. /meetings/{id}/attendees
	selectedRoute     *Route
}

func NewRequest(httpRequest *http.Request) *Request {
	return &Request{
		Request:        httpRequest,
		pathParameters: map[string]string{},
		attributes:     map[string]interface{}{},
	} // empty parameters, attributes
}

// If ContentType is missing or */* is given then fall back to this type, otherwise
// a "Unable to unmarshal content of type:" response is returned.
// Valid values are restful.MIME_JSON and restful.MIME_XML
// Example:
// 	restful.DefaultRequestContentType(restful.MIME_JSON)
func DefaultRequestContentType(mime string) {
	defaultRequestContentType = mime
}

// PathParameter accesses the Path parameter value by its name
func (r *Request) PathParameter(name string) string {
	return r.pathParameters[name]
}

// PathParameters accesses the Path parameter values
func (r *Request) PathParameters() map[string]string {
	return r.pathParameters
}

// QueryParameter returns the (first) Query parameter value by its name
func (r *Request) QueryParameter(name string) string {
	return r.Request.FormValue(name)
}

// QueryParameters returns the all the query parameters values by name
func (r *Request) QueryParameters(name string) []string {
	return r.Request.URL.Query()[name]
}

// BodyParameter parses the body of the request (once for typically a POST or a PUT) and returns the value of the given name or an error.
func (r *Request) BodyParameter(name string) (string, error) {
	err := r.Request.ParseForm()
	if err != nil {
		return "", err
	}
	return r.Request.PostFormValue(name), nil
}

// HeaderParameter returns the HTTP Header value of a Header name or empty if missing
func (r *Request) HeaderParameter(name string) string {
	return r.Request.Header.Get(name)
}

// ReadEntity checks the Accept header and reads the content into the entityPointer.
func (r *Request) ReadEntity(entityPointer interface{}) (err error) {
	contentType := r.Request.Header.Get(HEADER_ContentType)
	contentEncoding := r.Request.Header.Get(HEADER_ContentEncoding)

	// check if the request body needs decompression
	if ENCODING_GZIP == contentEncoding {
		gzipReader := currentCompressorProvider.AcquireGzipReader()
		defer currentCompressorProvider.ReleaseGzipReader(gzipReader)
		gzipReader.Reset(r.Request.Body)
		r.Request.Body = gzipReader
	} else if ENCODING_DEFLATE == contentEncoding {
		zlibReader, err := zlib.NewReader(r.Request.Body)
		if err != nil {
			return err
		}
		r.Request.Body = zlibReader
	}

	// lookup the EntityReader, use defaultRequestContentType if needed and provided
	entityReader, ok := entityAccessRegistry.accessorAt(contentType)
	if !ok {
		if len(defaultRequestContentType) != 0 {
			entityReader, ok = entityAccessRegistry.accessorAt(defaultRequestContentType)
		}
		if !ok {
			return NewError(http.StatusBadRequest, "Unable to unmarshal content of type:"+contentType)
		}
	}
	return entityReader.Read(r, entityPointer)
}

// SetAttribute adds or replaces the attribute with the given value.
func (r *Request) SetAttribute(name string, value interface{}) {
	r.attributes[name] = value
}

// Attribute returns the value associated to the given name. Returns nil if absent.
func (r Request) Attribute(name string) interface{} {
	return r.attributes[name]
}

// SelectedRoutePath root path + route path that matched the request, e.g. /meetings/{id}/attendees
func (r Request) SelectedRoutePath() string {
	return r.selectedRoute.Path
}

// SelectedRoute returns a reader to access the selected Route by the container
func (r Request) SelectedRoute() RouteReader {
	return routeAccessor{route: r.selectedRoute}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"path"
	"strings"

	"github.com/boltdb/bolt"
)

type Request struct {
	Service string
	Method  string
	Path    string
	Data    string

	Settings  Settings
	NoQueries bool
	NoHeaders bool

	URL url.URL

	verbose int
}

func (r *Request) Perform() (*http.Response, error) {
	if err := db.Update(request.LoadSettings); err != nil {
		return nil, err
	}

	req, err := r.Prepare()
	if err != nil {
		return nil, err
	}

	switch r.verbose {
	case 1:
		fmt.Println(request.URL.String())
	case 2, 3:
		// at level 3 display the raw request
		extra := false
		if r.verbose >= 3 {
			extra = true
		}

		dump, err := httputil.DumpRequestOut(req, extra)
		if err != nil {
			// this is only the verbose logging, so carry on in case of error
			fmt.Println(err)
			break
		}
		fmt.Println(string(dump))
	}

	client := &http.Client{}
	return client.Do(req)
}

// Prepare the http request.  This will substitute all the parameters,
// addd all the headers and query parameters
func (r *Request) Prepare() (*http.Request, error) {
	// prepare the url
	r.URL = r.Settings.URL()
	params := paramReplacer(r.Settings.Parameters)

	r.URL.Path = path.Join(r.Settings.BasePath.String, params.Replace(r.Path))
	r.Data = params.Replace(r.Data)

	if !r.NoQueries {
		q := r.URL.Query()
		for key, value := range r.Settings.Queries {
			q.Set(params.Replace(key), params.Replace(value))
		}
		r.URL.RawQuery = q.Encode()
	}

	// prepare the request
	req, err := http.NewRequest(
		strings.ToUpper(r.Method),
		r.URL.String(),
		strings.NewReader(r.Data),
	)
	if err != nil {
		return nil, err
	}

	if r.Settings.Username.Valid && r.Settings.Password.Valid {
		req.SetBasicAuth(r.Settings.Username.String, r.Settings.Password.String)
	}

	if !r.NoHeaders {
		for key, value := range r.Settings.Headers {
			req.Header.Set(params.Replace(key), params.Replace(value))
		}
	}

	return req, nil
}

// MakeServiceBucket creates the bucket for the service
func (r *Request) MakeServiceBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	if r.Service == "" {
		info := tx.Bucket([]byte("info"))
		current := info.Get([]byte("current"))
		r.Service = string(current)
	}

	sb, err := tx.CreateBucketIfNotExists([]byte("services"))
	if err != nil {
		return nil, err
	}

	b, err := sb.CreateBucketIfNotExists([]byte(r.Service))
	if err != nil {
		return nil, err
	}

	return b, nil
}

// ServiceBucket retrieves the bucket for the current requests service
func (r *Request) ServiceBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	if r.Service == "" {
		info := tx.Bucket([]byte("info"))
		current := info.Get([]byte("current"))
		r.Service = string(current)
	}

	if r.Service == "" {
		return nil, ErrNoServiceSet
	}

	sb := tx.Bucket([]byte("services"))
	if sb == nil {
		return nil, ErrNoServicesBucket
	}

	b := sb.Bucket([]byte(r.Service))
	if b == nil {
		return nil, ErrNoService{Name: r.Service}
	}

	return b, nil
}

// MakePathBucket creates the bucket for the path
func (r Request) MakePathBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	s, err := r.ServiceBucket(tx)
	if err != nil {
		return nil, err
	}

	pb, err := s.CreateBucketIfNotExists([]byte("paths"))
	if err != nil {
		return nil, err
	}

	b, err := pb.CreateBucketIfNotExists([]byte(r.Path))
	if err != nil {
		return nil, err
	}

	return b, nil
}

// PathBucket returns the bucket for the request path, creates if needed
func (r Request) PathBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	s, err := r.ServiceBucket(tx)
	if err != nil {
		return nil, err
	}

	pb := s.Bucket([]byte("paths"))
	if pb == nil {
		return nil, ErrNoPaths
	}

	b := pb.Bucket([]byte(r.Path))
	if b == nil {
		return nil, ErrInvalidPath{Path: r.Path}
	}

	return b, nil
}

// MakeMethodBucket returns the bucket for the request method, creates if needed
func (r Request) MakeMethodBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	s, err := r.PathBucket(tx)
	if err != nil {
		return nil, err
	}

	b, err := s.CreateBucketIfNotExists([]byte(r.Method))
	if err != nil {
		return nil, err
	}

	return b, nil
}

// LoadSettings from the database
func (r *Request) LoadSettings(tx *bolt.Tx) error {
	sb, pb, mb, err := request.Match(tx)
	if err != nil {
		return err
	}

	// Start with blank settings
	r.Settings = NewSettings()

	// load service settings
	if sb != nil {
		r.Settings = LoadSettings(sb)
	}

	// load path settings
	if pb != nil {
		r.Settings.Merge(LoadSettings(pb))
	}

	// load method settings
	if mb != nil {
		r.Settings.Merge(LoadSettings(mb))
	}

	// load provided cli flags settings
	r.Settings.Merge(settings)

	return nil
}

// Match returns the relavant db buckets for all requst settings
func (r Request) Match(tx *bolt.Tx) (service, path, method *bolt.Bucket, err error) {
	service, err = r.ServiceBucket(tx)
	if err != nil {
		return nil, nil, nil, err
	}

	pb := service.Bucket([]byte("paths"))
	if pb == nil {
		return service, nil, nil, nil
	}

	// Match the path, this will eventually be expanded to better match
	// the path.  So specific paths will be matched before generic ones
	// at the moment it requires an exact match
	c := pb.Cursor()
	for key, _ := c.First(); key != nil; key, _ = c.Next() {
		if string(key) == r.Path {
			path = pb.Bucket(key)
			break
		}
	}

	if path == nil {
		return service, path, nil, nil
	}

	method = path.Bucket([]byte(r.Method))

	return service, path, method, nil
}
<commit_msg>Fix panic when no services initialised<commit_after>package main

import (
	"fmt"
	"net/http"
	"net/http/httputil"
	"net/url"
	"path"
	"strings"

	"github.com/boltdb/bolt"
)

type Request struct {
	Service string
	Method  string
	Path    string
	Data    string

	Settings  Settings
	NoQueries bool
	NoHeaders bool

	URL url.URL

	verbose int
}

func (r *Request) Perform() (*http.Response, error) {
	if err := db.Update(request.LoadSettings); err != nil {
		return nil, err
	}

	req, err := r.Prepare()
	if err != nil {
		return nil, err
	}

	switch r.verbose {
	case 1:
		fmt.Println(request.URL.String())
	case 2, 3:
		// at level 3 display the raw request
		extra := false
		if r.verbose >= 3 {
			extra = true
		}

		dump, err := httputil.DumpRequestOut(req, extra)
		if err != nil {
			// this is only the verbose logging, so carry on in case of error
			fmt.Println(err)
			break
		}
		fmt.Println(string(dump))
	}

	client := &http.Client{}
	return client.Do(req)
}

// Prepare the http request.  This will substitute all the parameters,
// addd all the headers and query parameters
func (r *Request) Prepare() (*http.Request, error) {
	// prepare the url
	r.URL = r.Settings.URL()
	params := paramReplacer(r.Settings.Parameters)

	r.URL.Path = path.Join(r.Settings.BasePath.String, params.Replace(r.Path))
	r.Data = params.Replace(r.Data)

	if !r.NoQueries {
		q := r.URL.Query()
		for key, value := range r.Settings.Queries {
			q.Set(params.Replace(key), params.Replace(value))
		}
		r.URL.RawQuery = q.Encode()
	}

	// prepare the request
	req, err := http.NewRequest(
		strings.ToUpper(r.Method),
		r.URL.String(),
		strings.NewReader(r.Data),
	)
	if err != nil {
		return nil, err
	}

	if r.Settings.Username.Valid && r.Settings.Password.Valid {
		req.SetBasicAuth(r.Settings.Username.String, r.Settings.Password.String)
	}

	if !r.NoHeaders {
		for key, value := range r.Settings.Headers {
			req.Header.Set(params.Replace(key), params.Replace(value))
		}
	}

	return req, nil
}

// MakeServiceBucket creates the bucket for the service
func (r *Request) MakeServiceBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	if r.Service == "" {
		info := tx.Bucket([]byte("info"))
		current := info.Get([]byte("current"))
		r.Service = string(current)
	}

	sb, err := tx.CreateBucketIfNotExists([]byte("services"))
	if err != nil {
		return nil, err
	}

	b, err := sb.CreateBucketIfNotExists([]byte(r.Service))
	if err != nil {
		return nil, err
	}

	return b, nil
}

// ServiceBucket retrieves the bucket for the current requests service
func (r *Request) ServiceBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	if r.Service == "" {
		info := tx.Bucket([]byte("info"))
		if info == nil {
			return nil, ErrNoInfoBucket
		}
		current := info.Get([]byte("current"))
		r.Service = string(current)
	}

	if r.Service == "" {
		return nil, ErrNoServiceSet
	}

	sb := tx.Bucket([]byte("services"))
	if sb == nil {
		return nil, ErrNoServicesBucket
	}

	b := sb.Bucket([]byte(r.Service))
	if b == nil {
		return nil, ErrNoService{Name: r.Service}
	}

	return b, nil
}

// MakePathBucket creates the bucket for the path
func (r Request) MakePathBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	s, err := r.ServiceBucket(tx)
	if err != nil {
		return nil, err
	}

	pb, err := s.CreateBucketIfNotExists([]byte("paths"))
	if err != nil {
		return nil, err
	}

	b, err := pb.CreateBucketIfNotExists([]byte(r.Path))
	if err != nil {
		return nil, err
	}

	return b, nil
}

// PathBucket returns the bucket for the request path, creates if needed
func (r Request) PathBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	s, err := r.ServiceBucket(tx)
	if err != nil {
		return nil, err
	}

	pb := s.Bucket([]byte("paths"))
	if pb == nil {
		return nil, ErrNoPaths
	}

	b := pb.Bucket([]byte(r.Path))
	if b == nil {
		return nil, ErrInvalidPath{Path: r.Path}
	}

	return b, nil
}

// MakeMethodBucket returns the bucket for the request method, creates if needed
func (r Request) MakeMethodBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
	s, err := r.PathBucket(tx)
	if err != nil {
		return nil, err
	}

	b, err := s.CreateBucketIfNotExists([]byte(r.Method))
	if err != nil {
		return nil, err
	}

	return b, nil
}

// LoadSettings from the database
func (r *Request) LoadSettings(tx *bolt.Tx) error {
	sb, pb, mb, err := request.Match(tx)
	if err != nil {
		return err
	}

	// Start with blank settings
	r.Settings = NewSettings()

	// load service settings
	if sb != nil {
		r.Settings = LoadSettings(sb)
	}

	// load path settings
	if pb != nil {
		r.Settings.Merge(LoadSettings(pb))
	}

	// load method settings
	if mb != nil {
		r.Settings.Merge(LoadSettings(mb))
	}

	// load provided cli flags settings
	r.Settings.Merge(settings)

	return nil
}

// Match returns the relavant db buckets for all requst settings
func (r Request) Match(tx *bolt.Tx) (service, path, method *bolt.Bucket, err error) {
	service, err = r.ServiceBucket(tx)
	if err != nil {
		return nil, nil, nil, err
	}

	pb := service.Bucket([]byte("paths"))
	if pb == nil {
		return service, nil, nil, nil
	}

	// Match the path, this will eventually be expanded to better match
	// the path.  So specific paths will be matched before generic ones
	// at the moment it requires an exact match
	c := pb.Cursor()
	for key, _ := c.First(); key != nil; key, _ = c.Next() {
		if string(key) == r.Path {
			path = pb.Bucket(key)
			break
		}
	}

	if path == nil {
		return service, path, nil, nil
	}

	method = path.Bucket([]byte(r.Method))

	return service, path, method, nil
}
<|endoftext|>


<commit_before>/*
Package base provides some base functions such as random code and valid phoneNumber check
*/
package base

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/evolsnow/samaritan/common/log"
	"io/ioutil"
	"math/rand"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

const (
	AvatarPath = "static/avatar/"
)

//generate avatar url
func getGravatarUrl(phone string) string {
	email := fmt.Sprintf("%s@samaritan.tech", phone)
	h := md5.New()
	h.Write([]byte(email))
	hashed := hex.EncodeToString(h.Sum(nil))
	return fmt.Sprintf("https://cn.gravatar.com/avatar/%s.jpg?d=retro&s=40", hashed)
}

// GenerateAvatar saves avatar file and return relative path
func GenerateAvatar(phone string) (string, error) {
	resp, err := http.Get(getGravatarUrl(phone))
	if err == nil {
		defer resp.Body.Close()
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			//use default avatar
			return "", err
		}
		path := fmt.Sprintf("%s%s.jpg", AvatarPath, phone)
		err = ioutil.WriteFile(path, data, 0644)
		if err != nil {
			return "", err
		}
		return path, nil
	}
	return "", err
}

// RandomCodeSix generates random 6-length code
func RandomCodeSix() string {
	rand.Seed(time.Now().UTC().UnixNano())
	code := 100000 + rand.Intn(900000)
	return strconv.Itoa(code)
}

// ValidPhone checks if the phone number is legal
func ValidPhone(phone string) bool {
	pattern := regexp.MustCompile("(13[0-9]|15[01235678]|17[0-9]|18[0-9]|14[57])[0-9]{8}")
	return pattern.MatchString(phone)
}

// ValidMail checks if the mail format is legal
func ValidMail(mail string) bool {
	pattern := regexp.MustCompile("[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,4})")
	return pattern.MatchString(mail)
}

// ValidSamId checks if the sam id is legal
func ValidSamId(samId string) bool {
	pattern := regexp.MustCompile("^(\\w)+$")
	return pattern.MatchString(samId)
}

// BadReqErr means 400 bad request error
func BadReqErr(w http.ResponseWriter, desc string) {
	setError(w, desc, http.StatusBadRequest)
}

// ForbidErr means 403 forbidden error
func ForbidErr(w http.ResponseWriter, desc string) {
	setError(w, desc, http.StatusForbidden)
}

// MethodNAErr means 405 method not allowed error
func MethodNAErr(w http.ResponseWriter, desc string) {
	setError(w, desc, http.StatusMethodNotAllowed)
}

// UnAuthErr means 401 unauthorized error
func UnAuthErr(w http.ResponseWriter, desc string) {
	setError(w, desc, http.StatusUnauthorized)
}

// NotFoundErr means 404 not found error
func NotFoundErr(w http.ResponseWriter, desc string) {
	setError(w, desc, http.StatusNotFound)
}

// InternalErr means 500 internal error
func InternalErr(w http.ResponseWriter, desc string) {
	setError(w, desc, http.StatusInternalServerError)
}

//set http status and reply error
func setError(w http.ResponseWriter, desc string, status int) {
	e := map[string]interface{}{"code": status, "msg": desc}
	msg, _ := json.Marshal(e)
	log.DebugJson(e)
	w.WriteHeader(status)
	w.Write(msg)
}

// InIntSlice checks if an int is in the slice []int
func InIntSlice(a int, list []int) bool {
	for _, v := range list {
		if a == v {
			return true
		}
	}
	return false
}
<commit_msg>http code<commit_after>/*
Package base provides some base functions such as random code and valid phoneNumber check
*/
package base

import (
	"crypto/md5"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"github.com/evolsnow/samaritan/common/log"
	"io/ioutil"
	"math/rand"
	"net/http"
	"regexp"
	"strconv"
	"time"
)

const (
	AvatarPath = "static/avatar/"
)

//generate avatar url
func getGravatarUrl(phone string) string {
	email := fmt.Sprintf("%s@samaritan.tech", phone)
	h := md5.New()
	h.Write([]byte(email))
	hashed := hex.EncodeToString(h.Sum(nil))
	return fmt.Sprintf("https://cn.gravatar.com/avatar/%s.jpg?d=retro&s=40", hashed)
}

// GenerateAvatar saves avatar file and return relative path
func GenerateAvatar(phone string) (string, error) {
	resp, err := http.Get(getGravatarUrl(phone))
	if err == nil {
		defer resp.Body.Close()
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			//use default avatar
			return "", err
		}
		path := fmt.Sprintf("%s%s.jpg", AvatarPath, phone)
		err = ioutil.WriteFile(path, data, 0644)
		if err != nil {
			return "", err
		}
		return path, nil
	}
	return "", err
}

// RandomCodeSix generates random 6-length code
func RandomCodeSix() string {
	rand.Seed(time.Now().UTC().UnixNano())
	code := 100000 + rand.Intn(900000)
	return strconv.Itoa(code)
}

// ValidPhone checks if the phone number is legal
func ValidPhone(phone string) bool {
	pattern := regexp.MustCompile("(13[0-9]|15[01235678]|17[0-9]|18[0-9]|14[57])[0-9]{8}")
	return pattern.MatchString(phone)
}

// ValidMail checks if the mail format is legal
func ValidMail(mail string) bool {
	pattern := regexp.MustCompile("[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,4})")
	return pattern.MatchString(mail)
}

// ValidSamId checks if the sam id is legal
func ValidSamId(samId string) bool {
	pattern := regexp.MustCompile("^(\\w)+$")
	return pattern.MatchString(samId)
}

// BadReqErr means 400 bad request error
func BadReqErr(w http.ResponseWriter, desc string) {
	setError(w, desc, http.StatusBadRequest)
}

// ForbidErr means 403 forbidden error
func ForbidErr(w http.ResponseWriter, desc string) {
	setError(w, desc, http.StatusForbidden)
}

// MethodNAErr means 405 method not allowed error
func MethodNAErr(w http.ResponseWriter, desc string) {
	setError(w, desc, http.StatusMethodNotAllowed)
}

// UnAuthErr means 401 unauthorized error
func UnAuthErr(w http.ResponseWriter, desc string) {
	setError(w, desc, http.StatusUnauthorized)
}

// NotFoundErr means 404 not found error
func NotFoundErr(w http.ResponseWriter, desc string) {
	setError(w, desc, http.StatusNotFound)
}

// InternalErr means 500 internal error
func InternalErr(w http.ResponseWriter, desc string) {
	setError(w, desc, http.StatusInternalServerError)
}

//set http status and reply error
func setError(w http.ResponseWriter, desc string, status int) {
	e := map[string]interface{}{"code": status, "msg": desc}
	msg, _ := json.Marshal(e)
	log.DebugJson(e)
	//w.WriteHeader(status)
	w.Write(msg)
}

// InIntSlice checks if an int is in the slice []int
func InIntSlice(a int, list []int) bool {
	for _, v := range list {
		if a == v {
			return true
		}
	}
	return false
}
<|endoftext|>