<commit_before>// Copyright (c) 2012 The gocql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gocql

import (
	"io"
	"net"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
	"time"
)

type TestServer struct {
	Address  string
	t        *testing.T
	nreq     uint64
	listen   net.Listener
	nKillReq uint64
}

func TestSimple(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	db, err := NewCluster(srv.Address).CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	if err := db.Query("void").Exec(); err != nil {
		t.Error(err)
	}
}

func TestClosed(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	session, err := NewCluster(srv.Address).CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}
	session.Close()

	if err := session.Query("void").Exec(); err != ErrSessionClosed {
		t.Errorf("expected %#v, got %#v", ErrSessionClosed, err)
	}
}

func TestTimeout(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	db, err := NewCluster(srv.Address).CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	go func() {
		<-time.After(2 * time.Second)
		t.Fatal("no timeout")
	}()

	if err := db.Query("kill").Exec(); err == nil {
		t.Fatal("expected error")
	}
}

// TestQueryRetry will test to make sure that gocql will execute
// the exact amount of retry queries designated by the user.
func TestQueryRetry(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	db, err := NewCluster(srv.Address).CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	go func() {
		<-time.After(5 * time.Second)
		t.Fatal("no timeout")
	}()
	rt := RetryPolicy{NumRetries: 1}

	if err := db.Query("kill").RetryPolicy(rt).Exec(); err == nil {
		t.Fatal("expected error")
	}
	//Minus 1 from the nKillReq variable since there is the initial query attempt
	if srv.nKillReq-1 != uint64(rt.NumRetries) {
		t.Fatalf("failed to retry the query %v time(s). Query executed %v times", rt.NumRetries, srv.nKillReq-1)
	}
}

func TestSlowQuery(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	db, err := NewCluster(srv.Address).CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	if err := db.Query("slow").Exec(); err != nil {
		t.Fatal(err)
	}
}

func TestRoundRobin(t *testing.T) {
	servers := make([]*TestServer, 5)
	addrs := make([]string, len(servers))
	for i := 0; i < len(servers); i++ {
		servers[i] = NewTestServer(t)
		addrs[i] = servers[i].Address
		defer servers[i].Stop()
	}
	cluster := NewCluster(addrs...)
	db, err := cluster.CreateSession()
	time.Sleep(1 * time.Second) //Sleep to allow the Cluster.fillPool to complete

	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	var wg sync.WaitGroup
	wg.Add(5)
	for i := 0; i < 5; i++ {
		go func() {
			for j := 0; j < 5; j++ {
				if err := db.Query("void").Exec(); err != nil {
					t.Fatal(err)
				}
			}
			wg.Done()
		}()
	}
	wg.Wait()

	diff := 0
	for i := 1; i < len(servers); i++ {
		d := 0
		if servers[i].nreq > servers[i-1].nreq {
			d = int(servers[i].nreq - servers[i-1].nreq)
		} else {
			d = int(servers[i-1].nreq - servers[i].nreq)
		}
		if d > diff {
			diff = d
		}
	}

	if diff > 0 {
		t.Fatal("diff:", diff)
	}
}

func TestConnClosing(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	db, err := NewCluster(srv.Address).CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}
	defer db.Close()

	numConns := db.cfg.NumConns
	count := db.cfg.NumStreams * numConns

	wg := &sync.WaitGroup{}
	wg.Add(count)
	for i := 0; i < count; i++ {
		go func(wg *sync.WaitGroup) {
			wg.Done()
			db.Query("kill").Exec()
		}(wg)
	}

	wg.Wait()

	time.Sleep(1 * time.Second) //Sleep so the fillPool can complete.
	pool := db.Pool.(ConnectionPool)
	conns := pool.Size()

	if conns != numConns {
		t.Fatalf("Expected to have %d connections but have %d", numConns, conns)
	}
}

func TestConnectHander(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	called := false

	cluster_conf := NewCluster(srv.Address)
	cluster_conf.ConnectHandler = func(p ConnectionPool) {
		called = true
		if p.Size() <= 0 {
			t.Errorf("No new connection detected in pool: %v", p)
		}
	}

	db, err := cluster_conf.CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	// Run some query to make sure we connect
	// before checking that handler fired off
	if err := db.Query("void").Exec(); err != nil {
		t.Error(err)
	}

	if !called {
		t.Errorf("Connect handler not called")
	}
}

func TestDisconnectHander(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	called := false

	cluster_conf := NewCluster(srv.Address)
	cluster_conf.DisconnectHandler = func(p ConnectionPool) {
		called = true
	}

	db, err := cluster_conf.CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	// Run some query to make sure we connect
	if err := db.Query("void").Exec(); err != nil {
		t.Error(err)
	}

	// Run close to make sure we connect
	db.Close()

	if !called {
		t.Errorf("Disconnect handler not called")
	}
}

func NewTestServer(t *testing.T) *TestServer {
	laddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	listen, err := net.ListenTCP("tcp", laddr)
	if err != nil {
		t.Fatal(err)
	}
	srv := &TestServer{Address: listen.Addr().String(), listen: listen, t: t}
	go srv.serve()
	return srv
}

func (srv *TestServer) serve() {
	defer srv.listen.Close()
	for {
		conn, err := srv.listen.Accept()
		if err != nil {
			break
		}
		go func(conn net.Conn) {
			defer conn.Close()
			for {
				frame := srv.readFrame(conn)
				atomic.AddUint64(&srv.nreq, 1)
				srv.process(frame, conn)
			}
		}(conn)
	}
}

func (srv *TestServer) Stop() {
	srv.listen.Close()
}

func (srv *TestServer) process(frame frame, conn net.Conn) {
	switch frame[3] {
	case opStartup:
		frame = frame[:headerSize]
		frame.setHeader(protoResponse, 0, frame[2], opReady)
	case opQuery:
		input := frame
		input.skipHeader()
		query := strings.TrimSpace(input.readLongString())
		frame = frame[:headerSize]
		frame.setHeader(protoResponse, 0, frame[2], opResult)
		first := query
		if n := strings.Index(query, " "); n > 0 {
			first = first[:n]
		}
		switch strings.ToLower(first) {
		case "kill":
			atomic.AddUint64(&srv.nKillReq, 1)
			select {}
		case "slow":
			go func() {
				<-time.After(1 * time.Second)
				frame.writeInt(resultKindVoid)
				frame.setLength(len(frame) - headerSize)
				if _, err := conn.Write(frame); err != nil {
					return
				}
			}()
			return
		case "use":
			frame.writeInt(3)
			frame.writeString(strings.TrimSpace(query[3:]))
		case "void":
			frame.writeInt(resultKindVoid)
		default:
			frame.writeInt(resultKindVoid)
		}
	default:
		frame = frame[:headerSize]
		frame.setHeader(protoResponse, 0, frame[2], opError)
		frame.writeInt(0)
		frame.writeString("not supported")
	}
	frame.setLength(len(frame) - headerSize)
	if _, err := conn.Write(frame); err != nil {
		return
	}
}

func (srv *TestServer) readFrame(conn net.Conn) frame {
	frame := make(frame, headerSize, headerSize+512)
	if _, err := io.ReadFull(conn, frame); err != nil {
		srv.t.Fatal(err)
	}
	if n := frame.Length(); n > 0 {
		frame.grow(n)
		if _, err := io.ReadFull(conn, frame[headerSize:]); err != nil {
			srv.t.Fatal(err)
		}
	}
	return frame
}
<commit_msg>try dummy query to force disconnect<commit_after>// Copyright (c) 2012 The gocql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package gocql

import (
	"io"
	"net"
	"strings"
	"sync"
	"sync/atomic"
	"testing"
	"time"
)

type TestServer struct {
	Address  string
	t        *testing.T
	nreq     uint64
	listen   net.Listener
	nKillReq uint64
}

func TestSimple(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	db, err := NewCluster(srv.Address).CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	if err := db.Query("void").Exec(); err != nil {
		t.Error(err)
	}
}

func TestClosed(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	session, err := NewCluster(srv.Address).CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}
	session.Close()

	if err := session.Query("void").Exec(); err != ErrSessionClosed {
		t.Errorf("expected %#v, got %#v", ErrSessionClosed, err)
	}
}

func TestTimeout(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	db, err := NewCluster(srv.Address).CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	go func() {
		<-time.After(2 * time.Second)
		t.Fatal("no timeout")
	}()

	if err := db.Query("kill").Exec(); err == nil {
		t.Fatal("expected error")
	}
}

// TestQueryRetry will test to make sure that gocql will execute
// the exact amount of retry queries designated by the user.
func TestQueryRetry(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	db, err := NewCluster(srv.Address).CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	go func() {
		<-time.After(5 * time.Second)
		t.Fatal("no timeout")
	}()
	rt := RetryPolicy{NumRetries: 1}

	if err := db.Query("kill").RetryPolicy(rt).Exec(); err == nil {
		t.Fatal("expected error")
	}
	//Minus 1 from the nKillReq variable since there is the initial query attempt
	if srv.nKillReq-1 != uint64(rt.NumRetries) {
		t.Fatalf("failed to retry the query %v time(s). Query executed %v times", rt.NumRetries, srv.nKillReq-1)
	}
}

func TestSlowQuery(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	db, err := NewCluster(srv.Address).CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	if err := db.Query("slow").Exec(); err != nil {
		t.Fatal(err)
	}
}

func TestRoundRobin(t *testing.T) {
	servers := make([]*TestServer, 5)
	addrs := make([]string, len(servers))
	for i := 0; i < len(servers); i++ {
		servers[i] = NewTestServer(t)
		addrs[i] = servers[i].Address
		defer servers[i].Stop()
	}
	cluster := NewCluster(addrs...)
	db, err := cluster.CreateSession()
	time.Sleep(1 * time.Second) //Sleep to allow the Cluster.fillPool to complete

	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	var wg sync.WaitGroup
	wg.Add(5)
	for i := 0; i < 5; i++ {
		go func() {
			for j := 0; j < 5; j++ {
				if err := db.Query("void").Exec(); err != nil {
					t.Fatal(err)
				}
			}
			wg.Done()
		}()
	}
	wg.Wait()

	diff := 0
	for i := 1; i < len(servers); i++ {
		d := 0
		if servers[i].nreq > servers[i-1].nreq {
			d = int(servers[i].nreq - servers[i-1].nreq)
		} else {
			d = int(servers[i-1].nreq - servers[i].nreq)
		}
		if d > diff {
			diff = d
		}
	}

	if diff > 0 {
		t.Fatal("diff:", diff)
	}
}

func TestConnClosing(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	db, err := NewCluster(srv.Address).CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}
	defer db.Close()

	numConns := db.cfg.NumConns
	count := db.cfg.NumStreams * numConns

	wg := &sync.WaitGroup{}
	wg.Add(count)
	for i := 0; i < count; i++ {
		go func(wg *sync.WaitGroup) {
			wg.Done()
			db.Query("kill").Exec()
		}(wg)
	}

	wg.Wait()

	time.Sleep(1 * time.Second) //Sleep so the fillPool can complete.
	pool := db.Pool.(ConnectionPool)
	conns := pool.Size()

	if conns != numConns {
		t.Fatalf("Expected to have %d connections but have %d", numConns, conns)
	}
}

func TestConnectHander(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	called := false

	cluster_conf := NewCluster(srv.Address)
	cluster_conf.ConnectHandler = func(p ConnectionPool) {
		called = true
		if p.Size() <= 0 {
			t.Errorf("No new connection detected in pool: %v", p)
		}
	}

	db, err := cluster_conf.CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	// Run some query to make sure we connect
	// before checking that handler fired off
	if err := db.Query("void").Exec(); err != nil {
		t.Error(err)
	}

	if !called {
		t.Errorf("Connect handler not called")
	}
}

func TestDisconnectHander(t *testing.T) {
	srv := NewTestServer(t)
	defer srv.Stop()

	called := false

	cluster_conf := NewCluster(srv.Address)
	cluster_conf.DisconnectHandler = func(p ConnectionPool) {
		called = true
	}

	db, err := cluster_conf.CreateSession()
	if err != nil {
		t.Errorf("NewCluster: %v", err)
	}

	// Run some query to make sure we connect
	if err := db.Query("void").Exec(); err != nil {
		t.Error(err)
	}

	// Run close to make sure we connect
	db.Close()

	if err := db.Query("void").Exec(); err != ErrSessionClosed {
		t.Errorf("expected %#v, got %#v", ErrSessionClosed, err)
	}

	if !called {
		t.Errorf("Disconnect handler not called")
	}
}

func NewTestServer(t *testing.T) *TestServer {
	laddr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:0")
	if err != nil {
		t.Fatal(err)
	}
	listen, err := net.ListenTCP("tcp", laddr)
	if err != nil {
		t.Fatal(err)
	}
	srv := &TestServer{Address: listen.Addr().String(), listen: listen, t: t}
	go srv.serve()
	return srv
}

func (srv *TestServer) serve() {
	defer srv.listen.Close()
	for {
		conn, err := srv.listen.Accept()
		if err != nil {
			break
		}
		go func(conn net.Conn) {
			defer conn.Close()
			for {
				frame := srv.readFrame(conn)
				atomic.AddUint64(&srv.nreq, 1)
				srv.process(frame, conn)
			}
		}(conn)
	}
}

func (srv *TestServer) Stop() {
	srv.listen.Close()
}

func (srv *TestServer) process(frame frame, conn net.Conn) {
	switch frame[3] {
	case opStartup:
		frame = frame[:headerSize]
		frame.setHeader(protoResponse, 0, frame[2], opReady)
	case opQuery:
		input := frame
		input.skipHeader()
		query := strings.TrimSpace(input.readLongString())
		frame = frame[:headerSize]
		frame.setHeader(protoResponse, 0, frame[2], opResult)
		first := query
		if n := strings.Index(query, " "); n > 0 {
			first = first[:n]
		}
		switch strings.ToLower(first) {
		case "kill":
			atomic.AddUint64(&srv.nKillReq, 1)
			select {}
		case "slow":
			go func() {
				<-time.After(1 * time.Second)
				frame.writeInt(resultKindVoid)
				frame.setLength(len(frame) - headerSize)
				if _, err := conn.Write(frame); err != nil {
					return
				}
			}()
			return
		case "use":
			frame.writeInt(3)
			frame.writeString(strings.TrimSpace(query[3:]))
		case "void":
			frame.writeInt(resultKindVoid)
		default:
			frame.writeInt(resultKindVoid)
		}
	default:
		frame = frame[:headerSize]
		frame.setHeader(protoResponse, 0, frame[2], opError)
		frame.writeInt(0)
		frame.writeString("not supported")
	}
	frame.setLength(len(frame) - headerSize)
	if _, err := conn.Write(frame); err != nil {
		return
	}
}

func (srv *TestServer) readFrame(conn net.Conn) frame {
	frame := make(frame, headerSize, headerSize+512)
	if _, err := io.ReadFull(conn, frame); err != nil {
		srv.t.Fatal(err)
	}
	if n := frame.Length(); n > 0 {
		frame.grow(n)
		if _, err := io.ReadFull(conn, frame[headerSize:]); err != nil {
			srv.t.Fatal(err)
		}
	}
	return frame
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/albrow/qunit"
	"github.com/soroushjp/humble/rest"
	"reflect"
	"strconv"
)

type Todo struct {
	Id          int
	Title       string
	IsCompleted bool
}

func (t Todo) GetId() string {
	return strconv.Itoa(t.Id)
}

func (t Todo) RootURL() string {
	return "http://localhost:3000/todos"
}

func main() {
	qunit.Test("ReadAll", func(assert qunit.QUnitAssert) {
		qunit.Expect(2)
		done := assert.Call("async")
		go func() {
			expectedTodos := []*Todo{
				{
					Id:          0,
					Title:       "Todo 0",
					IsCompleted: false,
				},
				{
					Id:          1,
					Title:       "Todo 1",
					IsCompleted: false,
				},
				{
					Id:          2,
					Title:       "Todo 2",
					IsCompleted: true,
				},
			}
			gotTodos := []*Todo{}
			err := rest.ReadAll(&gotTodos)
			assert.Ok(err == nil, fmt.Sprintf("rest.ReadAll returned an error: %v", err))
			assert.Ok(reflect.DeepEqual(gotTodos, expectedTodos), fmt.Sprintf("Expected: %v, Got: %v", expectedTodos, gotTodos))
			done.Invoke()
		}()
	})

	qunit.Test("Read", func(assert qunit.QUnitAssert) {
		qunit.Expect(2)
		done := assert.Call("async")
		go func() {
			expectedTodo := &Todo{
				Id:          2,
				Title:       "Todo 2",
				IsCompleted: true,
			}
			gotTodo := &Todo{}
			err := rest.Read("2", gotTodo)
			assert.Ok(err == nil, fmt.Sprintf("rest.Read returned an error: %v", err))
			assert.Ok(reflect.DeepEqual(gotTodo, expectedTodo), fmt.Sprintf("Expected: %v, Got: %v", expectedTodo, gotTodo))
			done.Invoke()
		}()
	})

	qunit.Test("Create", func(assert qunit.QUnitAssert) {
		qunit.Expect(4)
		done := assert.Call("async")
		go func() {
			newTodo := &Todo{
				Title:       "Test",
				IsCompleted: true,
			}
			err := rest.Create(newTodo)
			assert.Ok(err == nil, fmt.Sprintf("rest.Create returned an error: %v", err))
			assert.Equal(newTodo.Id, 3, "newTodo.Id was not set correctly.")
			assert.Equal(newTodo.Title, "Test", "newTodo.Title was incorrect.")
			assert.Equal(newTodo.IsCompleted, true, "newTodo.IsCompleted was incorrect.")
			done.Invoke()
		}()
	})

	qunit.Test("Update", func(assert qunit.QUnitAssert) {
		qunit.Expect(4)
		done := assert.Call("async")
		go func() {
			updatedTodo := &Todo{
				Id:          1,
				Title:       "Updated Title",
				IsCompleted: true,
			}
			err := rest.Update(updatedTodo)
			assert.Ok(err == nil, fmt.Sprintf("rest.Update returned an error: %v", err))
			assert.Equal(updatedTodo.Id, 1, "updatedTodo.Id was incorrect.")
			assert.Equal(updatedTodo.Title, "Updated Title", "updatedTodo.Title was incorrect.")
			assert.Equal(updatedTodo.IsCompleted, true, "updatedTodo.IsCompleted was incorrect.")
			done.Invoke()
		}()
	})

	qunit.Test("Delete", func(assert qunit.QUnitAssert) {
		qunit.Expect(1)
		done := assert.Call("async")
		go func() {
			deletedTodo := &Todo{
				Id: 1,
			}
			err := rest.Delete(deletedTodo)
			assert.Ok(err == nil, fmt.Sprintf("rest.Update returned an error: %v", err))
			done.Invoke()
		}()
	})
}
<commit_msg>Rewrite import path to go-humble/humble<commit_after>package main

import (
	"fmt"
	"github.com/albrow/qunit"
	"github.com/go-humble/humble/rest"
	"reflect"
	"strconv"
)

type Todo struct {
	Id          int
	Title       string
	IsCompleted bool
}

func (t Todo) GetId() string {
	return strconv.Itoa(t.Id)
}

func (t Todo) RootURL() string {
	return "http://localhost:3000/todos"
}

func main() {
	qunit.Test("ReadAll", func(assert qunit.QUnitAssert) {
		qunit.Expect(2)
		done := assert.Call("async")
		go func() {
			expectedTodos := []*Todo{
				{
					Id:          0,
					Title:       "Todo 0",
					IsCompleted: false,
				},
				{
					Id:          1,
					Title:       "Todo 1",
					IsCompleted: false,
				},
				{
					Id:          2,
					Title:       "Todo 2",
					IsCompleted: true,
				},
			}
			gotTodos := []*Todo{}
			err := rest.ReadAll(&gotTodos)
			assert.Ok(err == nil, fmt.Sprintf("rest.ReadAll returned an error: %v", err))
			assert.Ok(reflect.DeepEqual(gotTodos, expectedTodos), fmt.Sprintf("Expected: %v, Got: %v", expectedTodos, gotTodos))
			done.Invoke()
		}()
	})

	qunit.Test("Read", func(assert qunit.QUnitAssert) {
		qunit.Expect(2)
		done := assert.Call("async")
		go func() {
			expectedTodo := &Todo{
				Id:          2,
				Title:       "Todo 2",
				IsCompleted: true,
			}
			gotTodo := &Todo{}
			err := rest.Read("2", gotTodo)
			assert.Ok(err == nil, fmt.Sprintf("rest.Read returned an error: %v", err))
			assert.Ok(reflect.DeepEqual(gotTodo, expectedTodo), fmt.Sprintf("Expected: %v, Got: %v", expectedTodo, gotTodo))
			done.Invoke()
		}()
	})

	qunit.Test("Create", func(assert qunit.QUnitAssert) {
		qunit.Expect(4)
		done := assert.Call("async")
		go func() {
			newTodo := &Todo{
				Title:       "Test",
				IsCompleted: true,
			}
			err := rest.Create(newTodo)
			assert.Ok(err == nil, fmt.Sprintf("rest.Create returned an error: %v", err))
			assert.Equal(newTodo.Id, 3, "newTodo.Id was not set correctly.")
			assert.Equal(newTodo.Title, "Test", "newTodo.Title was incorrect.")
			assert.Equal(newTodo.IsCompleted, true, "newTodo.IsCompleted was incorrect.")
			done.Invoke()
		}()
	})

	qunit.Test("Update", func(assert qunit.QUnitAssert) {
		qunit.Expect(4)
		done := assert.Call("async")
		go func() {
			updatedTodo := &Todo{
				Id:          1,
				Title:       "Updated Title",
				IsCompleted: true,
			}
			err := rest.Update(updatedTodo)
			assert.Ok(err == nil, fmt.Sprintf("rest.Update returned an error: %v", err))
			assert.Equal(updatedTodo.Id, 1, "updatedTodo.Id was incorrect.")
			assert.Equal(updatedTodo.Title, "Updated Title", "updatedTodo.Title was incorrect.")
			assert.Equal(updatedTodo.IsCompleted, true, "updatedTodo.IsCompleted was incorrect.")
			done.Invoke()
		}()
	})

	qunit.Test("Delete", func(assert qunit.QUnitAssert) {
		qunit.Expect(1)
		done := assert.Call("async")
		go func() {
			deletedTodo := &Todo{
				Id: 1,
			}
			err := rest.Delete(deletedTodo)
			assert.Ok(err == nil, fmt.Sprintf("rest.Update returned an error: %v", err))
			done.Invoke()
		}()
	})
}
<|endoftext|>


<commit_before>package controller

import (
	"app/app"
	"app/model"
	"app/mywebsocket"
	"context"
	"errors"
	"fmt"

	"github.com/goadesign/goa"
)

const (
	// 突然のエラー
	suddenlyPattern = "suddenly"
	// 使用変更
	changePattern = "change"
)

const (
	wsCollect = "wsCollect"
	wsMiss    = "wsMiss"
)

type storyInfo struct {
	resp          app.Storytype
	videoFileName string
	voiceFileName string
}

var (
	// ErrMissChoice 一致している選択がない場合のエラー
	ErrMissChoice = errors.New("incorrect choice")
	// ErrNotFoundStep 存在しない選択肢が選ばれた場合のエラー
	ErrNotFoundStep = errors.New("not found step")
	// ErrUnprocessableEntity 選択肢に存在するが、間違いを選択している場合のエラー
	ErrUnprocessableEntity = goa.NewErrorClass("unprocessable_entity", 422)
)

// StoriesController implements the story resource.
type StoriesController struct {
	*goa.Controller
	ws *mywebsocket.Server
}

// NewStoriesController creates a stories controller.
func NewStoriesController(service *goa.Service, ws *mywebsocket.Server) *StoriesController {
	return &StoriesController{
		Controller: service.NewController("StoriesController"),
		ws:         ws,
	}
}

// PlayStory runs the PlayStory action.
func (c *StoriesController) PlayStory(ctx *app.PlayStoryStoriesContext) error {
	// StoriesController_PlayStory: start_implement

	// Put your logic here
	now := ctx.NowStep
	t, err := model.GetTextByVoice(ctx, ctx.Request, "uploadfile")
	if err != nil {
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	isReturn, _ := model.IsReturn(t)
	if isReturn {
		ctx.ResponseData.Header().Set("Location", "/")
		return ctx.MovedPermanently()
	}
	si := storyInfo{}
	switch ctx.StoryPattern {
	case suddenlyPattern:
		si, err = suddenlyPatternStory(ctx, t, now)
	case changePattern:
		si, err = changePatternStory(ctx, t, now)
	}
	goa.LogInfo(ctx, "request now: now", "now", now)
	goa.LogInfo(ctx, "request user_answer: user_answer", "user_answer", t)
	if err != nil && err == model.ErrNotFoundChoice {
		v := mywebsocket.VideoChange{
			VideoFileName: "once_again.mp4",
			VoiceFileName: "once_again.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	if err != nil && err == ErrNotFoundStep {
		v := mywebsocket.VideoChange{
			VideoFileName: "stories_question.mp4",
			VoiceFileName: "stories_question.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	if err != nil && err == ErrMissChoice {
		v := mywebsocket.VideoChange{
			VideoFileName: "stories_question.mp4",
			VoiceFileName: "stories_question.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.UnprocessableEntity(ErrUnprocessableEntity(err))
	}
	if err != nil {
		v := mywebsocket.VideoChange{
			VideoFileName: "stories_question.mp4",
			VoiceFileName: "stories_question.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	// StoriesController_PlayStory: end_implement
	res := si.resp
	res.URL = fmt.Sprintf("/api/stories/%s/%d", res.StoryPattern, res.NextStep)
	res.UserVoiceText = t
	v := mywebsocket.VideoChange{
		VideoFileName: si.videoFileName,
		VoiceFileName: si.voiceFileName,
	}
	c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
	return ctx.OK(&res)
}

// SelectStory runs the SelectStory action.
func (c *StoriesController) SelectStory(ctx *app.SelectStoryStoriesContext) error {
	// StoriesController_SelectStory: start_implement

	// Put your logic here
	t, err := model.GetTextByVoice(ctx, ctx.Request, "uploadfile")
	if err != nil {
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	goa.LogInfo(ctx, "user_voice_text: t", "t", t)
	isReturn, _ := model.IsReturn(t)
	if isReturn {
		ctx.ResponseData.Header().Set("Location", "/")
		return ctx.MovedPermanently()
	}
	storiesDisplay := []string{suddenlyPattern, changePattern}
	stories := []string{"突然のエラー,とつぜんのエラー", "仕様変更,しようへんこう"}
	i, err := model.UserChoiceAnswer(stories, t)
	if err != nil {
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	si := storyInfo{}
	switch storiesDisplay[i] {
	case suddenlyPattern:
		si, err = suddenlyPatternStory(ctx, t, 1)
	case changePattern:
		si, err = changePatternStory(ctx, t, 1)
	}
	if err != nil && err == model.ErrNotFoundChoice {
		v := mywebsocket.VideoChange{
			VideoFileName: "once_again.mp4",
			VoiceFileName: "once_again.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	if err != nil && err == ErrNotFoundStep {
		v := mywebsocket.VideoChange{
			VideoFileName: "stories_question.mp4",
			VoiceFileName: "stories_question.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	if err != nil && err == ErrMissChoice {
		v := mywebsocket.VideoChange{
			VideoFileName: "stories_question.mp4",
			VoiceFileName: "stories_question.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.UnprocessableEntity(ErrUnprocessableEntity(err))
	}
	if err != nil {
		v := mywebsocket.VideoChange{
			VideoFileName: "stories_question.mp4",
			VoiceFileName: "stories_question.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	// StoriesController_PlayStory: end_implement
	res := si.resp
	res.URL = fmt.Sprintf("/api/stories/%s/%d", res.StoryPattern, res.NextStep)
	res.UserVoiceText = t
	v := mywebsocket.VideoChange{
		VideoFileName: si.videoFileName,
		VoiceFileName: si.voiceFileName,
	}
	c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)

	// StoriesController_SelectStory: end_implement
	return ctx.OK(&res)
}
func changePatternStory(ctx context.Context, t string, now int) (storyInfo, error) {
	s := app.Storytype{}
	si := storyInfo{}
	s.StoryPattern = changePattern
	cd1 := []string{"詳しい人へのアポ", "勝手に壊れた", "画面が映らない", "ネットに繋がらない"}
	c1 := []string{
		"詳しい人へのアポ,くわしいひとへのあぽ",
		"勝手に壊れた,かってにこわれた",
		"画面が映らない,がめんがうつらない",
		"ネットに繋がらない,ねっとにつならがない",
	}
	cd2 := []string{"114", "3327", "3639", "223"}
	cd3 := []string{"はい", "いいえ"}
	switch now {
	case 1:
		s.Question = "何かお困りですか？"
		s.Choices = cd1
		s.NextStep = 2
		s.Answer = cd1[0]
		si.resp = s
		si.videoFileName = "stories_change_1.mp4"
		si.voiceFileName = "stories_change_1.wav"
		return si, nil
	case 2:
		userChoices, err := model.UserChoiceAnswer(c1, t)
		if err != nil {
			goa.LogError(ctx, "changePatternStory 1: err", "err", err)
			return storyInfo{}, err
		}
		if cd1[userChoices] != cd1[0] {
			goa.LogError(ctx, "changePatternStory 2: err", "err", ErrMissChoice)
			return storyInfo{}, ErrMissChoice
		}
		s.Question = "プロジェクトIDを教えてください"
		s.Choices = cd2
		s.NextStep = 3
		s.Answer = cd2[0]
		si.resp = s
		si.videoFileName = "stories_change_2.mp4"
		si.voiceFileName = "stories_change_2.wav"
		return si, nil
	case 3:
		userChoices, err := model.UserChoiceAnswer(cd2, t)
		if err != nil {
			goa.LogError(ctx, "changePatternStory 3: err", "err", err)
			return storyInfo{}, err
		}
		if cd2[userChoices] != cd2[0] {
			goa.LogError(ctx, "changePatternStory 4: err", "err", ErrMissChoice)
			return storyInfo{}, ErrMissChoice
		}
		s.Question = "同期さんが詳しいようです。呼びますか？"
		s.Choices = cd3
		s.NextStep = 4
		s.Answer = cd3[0]
		si.resp = s
		si.videoFileName = "stories_change_3.mp4"
		si.voiceFileName = "stories_change_3.wav"
		return si, nil
	case 4:
		userChoices, err := model.UserChoiceAnswer(cd3, t)
		if err != nil {
			goa.LogError(ctx, "changePatternStory 5: err", "err", err)
			return storyInfo{}, err
		}
		if cd3[userChoices] != cd3[0] {
			goa.LogError(ctx, "changePatternStory 6: err", "err", ErrMissChoice)
			return storyInfo{}, ErrMissChoice
		}
		s.Question = "ストーリークリア"
		s.IsClear = true
		si.resp = s
		si.videoFileName = "stories_change_4.mp4"
		si.voiceFileName = "stories_change_4.wav"
		return si, nil
	default:
		return storyInfo{}, ErrNotFoundStep
	}
}

func suddenlyPatternStory(ctx context.Context, t string, now int) (storyInfo, error) {
	s := app.Storytype{}
	si := storyInfo{}
	s.StoryPattern = suddenlyPattern

	// ストーリーに使う選択肢
	cd1 := []string{"エラーが出てる", "勝手に壊れた", "画面が映らない", "ネットに繋がらない"}
	c1 := []string{
		"エラーが出てる,えらーがでてる",
		"勝手に壊れた,かってにこわれた",
		"画面が映らない,がめんがうつらない",
		"ネットに繋がらない,ねっとにつならがない",
	}
	cd2 := []string{"417", "114", "514", "1919"}
	cd3 := []string{"はい", "いいえ"}

	switch now {
	case 1:
		s.Question = "画面に何か出てますか？"
		s.Choices = cd1
		s.NextStep = 2
		s.Answer = cd1[0]
		si.resp = s
		si.videoFileName = "stories_suddenly_1.mp4"
		si.voiceFileName = "stories_suddenly_1.wav"
		return si, nil
	case 2:
		userChoices, err := model.UserChoiceAnswer(c1, t)
		if err != nil {
			goa.LogError(ctx, "suddenlyPatternStory 1: err", "err", err)
			return storyInfo{}, err
		}
		if cd1[userChoices] != cd1[0] {
			goa.LogError(ctx, "suddenlyPatternStory 2: err", "err", ErrMissChoice)
			return storyInfo{}, ErrMissChoice
		}
		s.Question = "エラーコードを教えてください"
		s.Choices = cd2
		s.NextStep = 3
		s.Answer = cd2[1]
		si.resp = s
		si.videoFileName = "stories_suddenly_2.mp4"
		si.voiceFileName = "stories_suddenly_2.wav"
		return si, nil
	case 3:
		userChoices, err := model.UserChoiceAnswer(cd2, t)
		if err != nil {
			goa.LogError(ctx, "suddenlyPatternStory 3: err", "err", err)
			return storyInfo{}, err
		}
		if cd2[userChoices] != cd2[1] {
			goa.LogError(ctx, "suddenlyPatternStory 4: err", "err", ErrMissChoice)
			return storyInfo{}, ErrMissChoice
		}
		s.Question = "担当者を呼びますか？"
		s.Choices = cd3
		s.NextStep = 4
		s.Answer = cd3[0]
		si.resp = s
		si.videoFileName = "stories_suddenly_3.mp4"
		si.voiceFileName = "stories_suddenly_3.wav"
		return si, nil
	case 4:
		userChoices, err := model.UserChoiceAnswer(cd3, t)
		if err != nil {
			goa.LogError(ctx, "suddenlyPatternStory 5: err", "err", err)
			return storyInfo{}, err
		}
		if cd3[userChoices] != cd3[0] {
			goa.LogError(ctx, "suddenlyPatternStory 6: err", "err", ErrMissChoice)
			return storyInfo{}, ErrMissChoice
		}
		s.Question = "ストーリークリア"
		s.IsClear = true
		si.resp = s
		si.videoFileName = "stories_suddenly_4.mp4"
		si.voiceFileName = "stories_suddenly_4.wav"
		return si, nil
	default:
		return storyInfo{}, ErrNotFoundStep
	}
}
<commit_msg>update: choice<commit_after>package controller

import (
	"app/app"
	"app/model"
	"app/mywebsocket"
	"context"
	"errors"
	"fmt"

	"github.com/goadesign/goa"
)

const (
	// 突然のエラー
	suddenlyPattern = "suddenly"
	// 使用変更
	changePattern = "change"
)

const (
	wsCollect = "wsCollect"
	wsMiss    = "wsMiss"
)

type storyInfo struct {
	resp          app.Storytype
	videoFileName string
	voiceFileName string
}

var (
	// ErrMissChoice 一致している選択がない場合のエラー
	ErrMissChoice = errors.New("incorrect choice")
	// ErrNotFoundStep 存在しない選択肢が選ばれた場合のエラー
	ErrNotFoundStep = errors.New("not found step")
	// ErrUnprocessableEntity 選択肢に存在するが、間違いを選択している場合のエラー
	ErrUnprocessableEntity = goa.NewErrorClass("unprocessable_entity", 422)
)

// StoriesController implements the story resource.
type StoriesController struct {
	*goa.Controller
	ws *mywebsocket.Server
}

// NewStoriesController creates a stories controller.
func NewStoriesController(service *goa.Service, ws *mywebsocket.Server) *StoriesController {
	return &StoriesController{
		Controller: service.NewController("StoriesController"),
		ws:         ws,
	}
}

// PlayStory runs the PlayStory action.
func (c *StoriesController) PlayStory(ctx *app.PlayStoryStoriesContext) error {
	// StoriesController_PlayStory: start_implement

	// Put your logic here
	now := ctx.NowStep
	t, err := model.GetTextByVoice(ctx, ctx.Request, "uploadfile")
	if err != nil {
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	isReturn, _ := model.IsReturn(t)
	if isReturn {
		ctx.ResponseData.Header().Set("Location", "/")
		return ctx.MovedPermanently()
	}
	si := storyInfo{}
	switch ctx.StoryPattern {
	case suddenlyPattern:
		si, err = suddenlyPatternStory(ctx, t, now)
	case changePattern:
		si, err = changePatternStory(ctx, t, now)
	}
	goa.LogInfo(ctx, "request now: now", "now", now)
	goa.LogInfo(ctx, "request user_answer: user_answer", "user_answer", t)
	if err != nil && err == model.ErrNotFoundChoice {
		v := mywebsocket.VideoChange{
			VideoFileName: "once_again.mp4",
			VoiceFileName: "once_again.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	if err != nil && err == ErrNotFoundStep {
		v := mywebsocket.VideoChange{
			VideoFileName: "stories_question.mp4",
			VoiceFileName: "stories_question.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	if err != nil && err == ErrMissChoice {
		v := mywebsocket.VideoChange{
			VideoFileName: "stories_question.mp4",
			VoiceFileName: "stories_question.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.UnprocessableEntity(ErrUnprocessableEntity(err))
	}
	if err != nil {
		v := mywebsocket.VideoChange{
			VideoFileName: "stories_question.mp4",
			VoiceFileName: "stories_question.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	// StoriesController_PlayStory: end_implement
	res := si.resp
	res.URL = fmt.Sprintf("/api/stories/%s/%d", res.StoryPattern, res.NextStep)
	res.UserVoiceText = t
	v := mywebsocket.VideoChange{
		VideoFileName: si.videoFileName,
		VoiceFileName: si.voiceFileName,
	}
	c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
	return ctx.OK(&res)
}

// SelectStory runs the SelectStory action.
func (c *StoriesController) SelectStory(ctx *app.SelectStoryStoriesContext) error {
	// StoriesController_SelectStory: start_implement

	// Put your logic here
	t, err := model.GetTextByVoice(ctx, ctx.Request, "uploadfile")
	if err != nil {
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	goa.LogInfo(ctx, "user_voice_text: t", "t", t)
	isReturn, _ := model.IsReturn(t)
	if isReturn {
		ctx.ResponseData.Header().Set("Location", "/")
		return ctx.MovedPermanently()
	}
	storiesDisplay := []string{suddenlyPattern, changePattern}
	stories := []string{"突然のエラー,とつぜんのエラー", "仕様変更,しようへんこう"}
	i, err := model.UserChoiceAnswer(stories, t)
	if err != nil {
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	si := storyInfo{}
	switch storiesDisplay[i] {
	case suddenlyPattern:
		si, err = suddenlyPatternStory(ctx, t, 1)
	case changePattern:
		si, err = changePatternStory(ctx, t, 1)
	}
	if err != nil && err == model.ErrNotFoundChoice {
		v := mywebsocket.VideoChange{
			VideoFileName: "once_again.mp4",
			VoiceFileName: "once_again.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	if err != nil && err == ErrNotFoundStep {
		v := mywebsocket.VideoChange{
			VideoFileName: "stories_question.mp4",
			VoiceFileName: "stories_question.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	if err != nil && err == ErrMissChoice {
		v := mywebsocket.VideoChange{
			VideoFileName: "stories_question.mp4",
			VoiceFileName: "stories_question.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.UnprocessableEntity(ErrUnprocessableEntity(err))
	}
	if err != nil {
		v := mywebsocket.VideoChange{
			VideoFileName: "stories_question.mp4",
			VoiceFileName: "stories_question.wav",
		}
		c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)
		return ctx.BadRequest(goa.ErrBadRequest(err))
	}
	// StoriesController_PlayStory: end_implement
	res := si.resp
	res.URL = fmt.Sprintf("/api/stories/%s/%d", res.StoryPattern, res.NextStep)
	res.UserVoiceText = t
	v := mywebsocket.VideoChange{
		VideoFileName: si.videoFileName,
		VoiceFileName: si.voiceFileName,
	}
	c.ws.Send(mywebsocket.WsMovieChannel, mywebsocket.WsVideoChange, v)

	// StoriesController_SelectStory: end_implement
	return ctx.OK(&res)
}
func changePatternStory(ctx context.Context, t string, now int) (storyInfo, error) {
	s := app.Storytype{}
	si := storyInfo{}
	s.StoryPattern = changePattern
	cd1 := []string{"詳しい人へのアポ", "勝手に壊れた", "画面が映らない", "ネットに繋がらない"}
	c1 := []string{
		"詳しい人へのアポ,くわしいひとへのあぽ",
		"勝手に壊れた,かってにこわれた",
		"画面が映らない,がめんがうつらない",
		"ネットに繋がらない,ねっとにつならがない",
	}
	cd2 := []string{"427", "3327", "3639", "223"}
	cd3 := []string{"はい", "いいえ"}
	switch now {
	case 1:
		s.Question = "何かお困りですか？"
		s.Choices = cd1
		s.NextStep = 2
		s.Answer = cd1[0]
		si.resp = s
		si.videoFileName = "stories_change_1.mp4"
		si.voiceFileName = "stories_change_1.wav"
		return si, nil
	case 2:
		userChoices, err := model.UserChoiceAnswer(c1, t)
		if err != nil {
			goa.LogError(ctx, "changePatternStory 1: err", "err", err)
			return storyInfo{}, err
		}
		if cd1[userChoices] != cd1[0] {
			goa.LogError(ctx, "changePatternStory 2: err", "err", ErrMissChoice)
			return storyInfo{}, ErrMissChoice
		}
		s.Question = "プロジェクトIDを教えてください"
		s.Choices = cd2
		s.NextStep = 3
		s.Answer = cd2[0]
		si.resp = s
		si.videoFileName = "stories_change_2.mp4"
		si.voiceFileName = "stories_change_2.wav"
		return si, nil
	case 3:
		userChoices, err := model.UserChoiceAnswer(cd2, t)
		if err != nil {
			goa.LogError(ctx, "changePatternStory 3: err", "err", err)
			return storyInfo{}, err
		}
		if cd2[userChoices] != cd2[0] {
			goa.LogError(ctx, "changePatternStory 4: err", "err", ErrMissChoice)
			return storyInfo{}, ErrMissChoice
		}
		s.Question = "同期さんが詳しいようです。呼びますか？"
		s.Choices = cd3
		s.NextStep = 4
		s.Answer = cd3[0]
		si.resp = s
		si.videoFileName = "stories_change_3.mp4"
		si.voiceFileName = "stories_change_3.wav"
		return si, nil
	case 4:
		userChoices, err := model.UserChoiceAnswer(cd3, t)
		if err != nil {
			goa.LogError(ctx, "changePatternStory 5: err", "err", err)
			return storyInfo{}, err
		}
		if cd3[userChoices] != cd3[0] {
			goa.LogError(ctx, "changePatternStory 6: err", "err", ErrMissChoice)
			return storyInfo{}, ErrMissChoice
		}
		s.Question = "ストーリークリア"
		s.IsClear = true
		si.resp = s
		si.videoFileName = "stories_change_4.mp4"
		si.voiceFileName = "stories_change_4.wav"
		return si, nil
	default:
		return storyInfo{}, ErrNotFoundStep
	}
}

func suddenlyPatternStory(ctx context.Context, t string, now int) (storyInfo, error) {
	s := app.Storytype{}
	si := storyInfo{}
	s.StoryPattern = suddenlyPattern

	// ストーリーに使う選択肢
	cd1 := []string{"エラーが出てる", "勝手に壊れた", "画面が映らない", "ネットに繋がらない"}
	c1 := []string{
		"エラーが出てる,えらーがでてる",
		"勝手に壊れた,かってにこわれた",
		"画面が映らない,がめんがうつらない",
		"ネットに繋がらない,ねっとにつならがない",
	}
	cd2 := []string{"427", "114", "514", "1919"}
	cd3 := []string{"はい", "いいえ"}

	switch now {
	case 1:
		s.Question = "画面に何か出てますか？"
		s.Choices = cd1
		s.NextStep = 2
		s.Answer = cd1[0]
		si.resp = s
		si.videoFileName = "stories_suddenly_1.mp4"
		si.voiceFileName = "stories_suddenly_1.wav"
		return si, nil
	case 2:
		userChoices, err := model.UserChoiceAnswer(c1, t)
		if err != nil {
			goa.LogError(ctx, "suddenlyPatternStory 1: err", "err", err)
			return storyInfo{}, err
		}
		if cd1[userChoices] != cd1[0] {
			goa.LogError(ctx, "suddenlyPatternStory 2: err", "err", ErrMissChoice)
			return storyInfo{}, ErrMissChoice
		}
		s.Question = "エラーコードを教えてください"
		s.Choices = cd2
		s.NextStep = 3
		s.Answer = cd2[1]
		si.resp = s
		si.videoFileName = "stories_suddenly_2.mp4"
		si.voiceFileName = "stories_suddenly_2.wav"
		return si, nil
	case 3:
		userChoices, err := model.UserChoiceAnswer(cd2, t)
		if err != nil {
			goa.LogError(ctx, "suddenlyPatternStory 3: err", "err", err)
			return storyInfo{}, err
		}
		if cd2[userChoices] != cd2[1] {
			goa.LogError(ctx, "suddenlyPatternStory 4: err", "err", ErrMissChoice)
			return storyInfo{}, ErrMissChoice
		}
		s.Question = "担当者を呼びますか？"
		s.Choices = cd3
		s.NextStep = 4
		s.Answer = cd3[0]
		si.resp = s
		si.videoFileName = "stories_suddenly_3.mp4"
		si.voiceFileName = "stories_suddenly_3.wav"
		return si, nil
	case 4:
		userChoices, err := model.UserChoiceAnswer(cd3, t)
		if err != nil {
			goa.LogError(ctx, "suddenlyPatternStory 5: err", "err", err)
			return storyInfo{}, err
		}
		if cd3[userChoices] != cd3[0] {
			goa.LogError(ctx, "suddenlyPatternStory 6: err", "err", ErrMissChoice)
			return storyInfo{}, ErrMissChoice
		}
		s.Question = "ストーリークリア"
		s.IsClear = true
		si.resp = s
		si.videoFileName = "stories_suddenly_4.mp4"
		si.voiceFileName = "stories_suddenly_4.wav"
		return si, nil
	default:
		return storyInfo{}, ErrNotFoundStep
	}
}
<|endoftext|>


<commit_before>package tlfupgrade

import (
	"context"
	"testing"
	"time"

	"github.com/keybase/client/go/kbtest"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/clockwork"
	"github.com/stretchr/testify/require"
)

type testAPIServer struct {
	libkb.API
	responseFn func() getUpgradeRes
}

func (t *testAPIServer) GetDecode(arg libkb.APIArg, resp libkb.APIResponseWrapper) error {
	*(resp.(*getUpgradeRes)) = t.responseFn()
	return nil
}

type testChatHelper struct {
	libkb.ChatHelper
}

func (t *testChatHelper) UpgradeKBFSToImpteam(context.Context, string, chat1.TLFID, bool) error {
	return nil
}

func TestBackgroundTLFUpdater(t *testing.T) {
	tc := libkb.SetupTest(t, "TestBackgroundTLFUpdater", 1)
	defer tc.Cleanup()
	_, err := kbtest.CreateAndSignupFakeUser("gregr", tc.G)
	require.NoError(t, err)

	api := &testAPIServer{}
	u := NewBackgroundTLFUpdater(tc.G)
	u.testingAPIServer = api
	u.testingChatHelper = &testChatHelper{}
	upgradeCh := make(chan keybase1.TLFID, 5)
	u.upgradeCh = &upgradeCh

	refTLFID := keybase1.TLFID("hi")
	f := func() getUpgradeRes {
		return getUpgradeRes{
			GetTLFForUpgradeRes: NewGetTLFForUpgradeResWithTlfavailable(GetTLFForUpgradeAvailableRes{
				TlfID: refTLFID,
			})}
	}
	api.responseFn = f
	clock := clockwork.NewFakeClock()
	u.clock = clock
	u.Run()
	attempt := func() {
		clock.BlockUntil(1)
		clock.Advance(time.Hour)
		select {
		case tlfID := <-upgradeCh:
			require.Equal(t, refTLFID, tlfID)
		case <-time.After(20 * time.Second):
			require.Fail(t, "no upgrade")
		}
	}
	attempt()
	tc.G.AppState.Update(keybase1.AppState_BACKGROUND)
	tc.G.AppState.Update(keybase1.AppState_FOREGROUND)
	attempt()
	u.Shutdown()
}
<commit_msg>use BlockUntil correct in tlf upgrade test<commit_after>package tlfupgrade

import (
	"context"
	"testing"
	"time"

	"github.com/keybase/client/go/kbtest"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/clockwork"
	"github.com/stretchr/testify/require"
)

type testAPIServer struct {
	libkb.API
	responseFn func() getUpgradeRes
}

func (t *testAPIServer) GetDecode(arg libkb.APIArg, resp libkb.APIResponseWrapper) error {
	*(resp.(*getUpgradeRes)) = t.responseFn()
	return nil
}

type testChatHelper struct {
	libkb.ChatHelper
}

func (t *testChatHelper) UpgradeKBFSToImpteam(context.Context, string, chat1.TLFID, bool) error {
	return nil
}

func TestBackgroundTLFUpdater(t *testing.T) {
	tc := libkb.SetupTest(t, "TestBackgroundTLFUpdater", 1)
	defer tc.Cleanup()
	_, err := kbtest.CreateAndSignupFakeUser("gregr", tc.G)
	require.NoError(t, err)

	api := &testAPIServer{}
	u := NewBackgroundTLFUpdater(tc.G)
	u.testingAPIServer = api
	u.testingChatHelper = &testChatHelper{}
	upgradeCh := make(chan keybase1.TLFID, 5)
	u.upgradeCh = &upgradeCh

	refTLFID := keybase1.TLFID("hi")
	f := func() getUpgradeRes {
		return getUpgradeRes{
			GetTLFForUpgradeRes: NewGetTLFForUpgradeResWithTlfavailable(GetTLFForUpgradeAvailableRes{
				TlfID: refTLFID,
			})}
	}
	api.responseFn = f
	clock := clockwork.NewFakeClock()
	u.clock = clock
	u.Run()
	attempt := func(attempt int) {
		clock.BlockUntil(attempt)
		clock.Advance(time.Hour)
		select {
		case tlfID := <-upgradeCh:
			require.Equal(t, refTLFID, tlfID)
		case <-time.After(20 * time.Second):
			require.Fail(t, "no upgrade")
		}
	}
	attempt(1)
	tc.G.AppState.Update(keybase1.AppState_BACKGROUND)
	tc.G.AppState.Update(keybase1.AppState_FOREGROUND)
	attempt(2)
	u.Shutdown()
}
<|endoftext|>


<commit_before>// Copyright ©2015 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package path

import (
	"gonum.org/v1/gonum/graph"
	"gonum.org/v1/gonum/graph/internal/linear"
)

// BellmanFordFrom returns a shortest-path tree for a shortest path from u to all nodes in
// the graph g, or false indicating that a negative cycle exists in the graph. If the graph
// does not implement Weighted, UniformCost is used.
//
// The time complexity of BellmanFordFrom is O(|V|.|E|).
func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
	if g.Node(u.ID()) == nil {
		return Shortest{from: u}, true
	}
	var weight Weighting
	if wg, ok := g.(Weighted); ok {
		weight = wg.Weight
	} else {
		weight = UniformCost(g)
	}

	nodes := graph.NodesOf(g.Nodes())

	path = newShortestFrom(u, nodes)
	path.dist[path.indexOf[u.ID()]] = 0
	path.negCosts = make(map[negEdge]float64)

	// Queue to keep track which nodes need to be relaxed.
	// Only nodes whose vertex distance changed in the previous iterations
	// need to be relaxed again.
	queue := newBellmanFordQueue(path.indexOf)
	queue.enqueue(u)

	// The maximum number of edges in a graph is |V| * (|V|-1) which is also
	// the worst case complexity.
	// If the queue-loop has more iterations than the amount of maximum edges
	// it indicates that we have a negative cycle.
	maxEdges := len(nodes) * (len(nodes) - 1)
	var loops int

	// TODO(kortschak): Consider adding further optimisations
	// from http://arxiv.org/abs/1111.5414.
	for queue.len() != 0 {
		u := queue.dequeue()
		uid := u.ID()
		j := path.indexOf[uid]

		to := g.From(uid)
		for to.Next() {
			v := to.Node()
			vid := v.ID()
			k := path.indexOf[vid]
			w, ok := weight(uid, vid)
			if !ok {
				panic("bellman-ford: unexpected invalid weight")
			}

			joint := path.dist[j] + w
			if joint < path.dist[k] {
				path.set(k, joint, j)

				if !queue.has(vid) {
					queue.enqueue(v)
				}
			}
		}

		if loops > maxEdges {
			path.hasNegativeCycle = true
			return path, false
		}
		loops++
	}

	return path, true
}

// BellmanFordAllFrom returns a shortest-path tree for shortest paths from u to all nodes in
// the graph g, or false indicating that a negative cycle exists in the graph. If the graph
// does not implement Weighted, UniformCost is used.
//
// The time complexity of BellmanFordAllFrom is O(|V|.|E|).
func BellmanFordAllFrom(u graph.Node, g graph.Graph) (path ShortestAlts, ok bool) {
	if g.Node(u.ID()) == nil {
		return ShortestAlts{from: u}, true
	}
	var weight Weighting
	if wg, ok := g.(Weighted); ok {
		weight = wg.Weight
	} else {
		weight = UniformCost(g)
	}

	nodes := graph.NodesOf(g.Nodes())

	path = newShortestAltsFrom(u, nodes)
	path.dist[path.indexOf[u.ID()]] = 0
	path.negCosts = make(map[negEdge]float64)

	// Queue to keep track which nodes need to be relaxed.
	// Only nodes whose vertex distance changed in the previous iterations
	// need to be relaxed again.
	queue := newBellmanFordQueue(path.indexOf)
	queue.enqueue(u)

	// The maximum number of edges in a graph is |V| * (|V|-1) which is also
	// the worst case complexity.
	// If the queue-loop has more iterations than the amount of maximum edges
	// it indicates that we have a negative cycle.
	maxEdges := len(nodes) * (len(nodes) - 1)
	var loops int

	// TODO(kortschak): Consider adding further optimisations
	// from http://arxiv.org/abs/1111.5414.
	for queue.len() != 0 {
		u := queue.dequeue()
		uid := u.ID()
		j := path.indexOf[uid]

		for _, v := range graph.NodesOf(g.From(uid)) {
			vid := v.ID()
			k := path.indexOf[vid]
			w, ok := weight(uid, vid)
			if !ok {
				panic("bellman-ford: unexpected invalid weight")
			}

			joint := path.dist[j] + w
			if joint < path.dist[k] {
				path.set(k, joint, j)

				if !queue.has(vid) {
					queue.enqueue(v)
				}
			} else if joint == path.dist[k] {
				path.addPath(k, j)
			}
		}

		if loops > maxEdges {
			path.hasNegativeCycle = true
			return path, false
		}
		loops++
	}

	return path, true
}

// bellmanFordQueue is a queue for the Queue-based Bellman-Ford algorithm.
type bellmanFordQueue struct {
	// queue holds the nodes which need to be relaxed.
	queue linear.NodeQueue

	// onQueue keeps track whether a node is on the queue or not.
	onQueue []bool

	// indexOf contains a mapping holding the id of a node with its index in the onQueue array.
	indexOf map[int64]int
}

// enqueue adds a node to the bellmanFordQueue.
func (q *bellmanFordQueue) enqueue(n graph.Node) {
	i := q.indexOf[n.ID()]
	if q.onQueue[i] {
		panic("bellman-ford: already queued")
	}
	q.onQueue[i] = true
	q.queue.Enqueue(n)
}

// dequeue returns the first value of the bellmanFordQueue.
func (q *bellmanFordQueue) dequeue() graph.Node {
	n := q.queue.Dequeue()
	q.onQueue[q.indexOf[n.ID()]] = false
	return n
}

// len returns the number of nodes in the bellmanFordQueue.
func (q *bellmanFordQueue) len() int { return q.queue.Len() }

// has returns whether a node with the given id is in the queue.
func (q bellmanFordQueue) has(id int64) bool { return q.onQueue[q.indexOf[id]] }

// newBellmanFordQueue creates a new bellmanFordQueue.
func newBellmanFordQueue(indexOf map[int64]int) bellmanFordQueue {
	return bellmanFordQueue{
		onQueue: make([]bool, len(indexOf)),
		indexOf: indexOf,
	}
}
<commit_msg>graph/path: fix Bellman-Ford negative cycle detection for 32 bit architectures<commit_after>// Copyright ©2015 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package path

import (
	"gonum.org/v1/gonum/graph"
	"gonum.org/v1/gonum/graph/internal/linear"
)

// BellmanFordFrom returns a shortest-path tree for a shortest path from u to all nodes in
// the graph g, or false indicating that a negative cycle exists in the graph. If the graph
// does not implement Weighted, UniformCost is used.
//
// The time complexity of BellmanFordFrom is O(|V|.|E|).
func BellmanFordFrom(u graph.Node, g graph.Graph) (path Shortest, ok bool) {
	if g.Node(u.ID()) == nil {
		return Shortest{from: u}, true
	}
	var weight Weighting
	if wg, ok := g.(Weighted); ok {
		weight = wg.Weight
	} else {
		weight = UniformCost(g)
	}

	nodes := graph.NodesOf(g.Nodes())

	path = newShortestFrom(u, nodes)
	path.dist[path.indexOf[u.ID()]] = 0
	path.negCosts = make(map[negEdge]float64)

	// Queue to keep track which nodes need to be relaxed.
	// Only nodes whose vertex distance changed in the previous iterations
	// need to be relaxed again.
	queue := newBellmanFordQueue(path.indexOf)
	queue.enqueue(u)

	// The maximum number of edges in a graph is |V| * (|V|-1) which is also
	// the worst case complexity.
	// If the queue-loop has more iterations than the amount of maximum edges
	// it indicates that we have a negative cycle.
	maxEdges := int64(len(nodes)) * int64(len(nodes)-1)
	var loops int64

	// TODO(kortschak): Consider adding further optimisations
	// from http://arxiv.org/abs/1111.5414.
	for queue.len() != 0 {
		u := queue.dequeue()
		uid := u.ID()
		j := path.indexOf[uid]

		to := g.From(uid)
		for to.Next() {
			v := to.Node()
			vid := v.ID()
			k := path.indexOf[vid]
			w, ok := weight(uid, vid)
			if !ok {
				panic("bellman-ford: unexpected invalid weight")
			}

			joint := path.dist[j] + w
			if joint < path.dist[k] {
				path.set(k, joint, j)

				if !queue.has(vid) {
					queue.enqueue(v)
				}
			}
		}

		if loops > maxEdges {
			path.hasNegativeCycle = true
			return path, false
		}
		loops++
	}

	return path, true
}

// BellmanFordAllFrom returns a shortest-path tree for shortest paths from u to all nodes in
// the graph g, or false indicating that a negative cycle exists in the graph. If the graph
// does not implement Weighted, UniformCost is used.
//
// The time complexity of BellmanFordAllFrom is O(|V|.|E|).
func BellmanFordAllFrom(u graph.Node, g graph.Graph) (path ShortestAlts, ok bool) {
	if g.Node(u.ID()) == nil {
		return ShortestAlts{from: u}, true
	}
	var weight Weighting
	if wg, ok := g.(Weighted); ok {
		weight = wg.Weight
	} else {
		weight = UniformCost(g)
	}

	nodes := graph.NodesOf(g.Nodes())

	path = newShortestAltsFrom(u, nodes)
	path.dist[path.indexOf[u.ID()]] = 0
	path.negCosts = make(map[negEdge]float64)

	// Queue to keep track which nodes need to be relaxed.
	// Only nodes whose vertex distance changed in the previous iterations
	// need to be relaxed again.
	queue := newBellmanFordQueue(path.indexOf)
	queue.enqueue(u)

	// The maximum number of edges in a graph is |V| * (|V|-1) which is also
	// the worst case complexity.
	// If the queue-loop has more iterations than the amount of maximum edges
	// it indicates that we have a negative cycle.
	maxEdges := int64(len(nodes)) * int64(len(nodes)-1)
	var loops int64

	// TODO(kortschak): Consider adding further optimisations
	// from http://arxiv.org/abs/1111.5414.
	for queue.len() != 0 {
		u := queue.dequeue()
		uid := u.ID()
		j := path.indexOf[uid]

		for _, v := range graph.NodesOf(g.From(uid)) {
			vid := v.ID()
			k := path.indexOf[vid]
			w, ok := weight(uid, vid)
			if !ok {
				panic("bellman-ford: unexpected invalid weight")
			}

			joint := path.dist[j] + w
			if joint < path.dist[k] {
				path.set(k, joint, j)

				if !queue.has(vid) {
					queue.enqueue(v)
				}
			} else if joint == path.dist[k] {
				path.addPath(k, j)
			}
		}

		if loops > maxEdges {
			path.hasNegativeCycle = true
			return path, false
		}
		loops++
	}

	return path, true
}

// bellmanFordQueue is a queue for the Queue-based Bellman-Ford algorithm.
type bellmanFordQueue struct {
	// queue holds the nodes which need to be relaxed.
	queue linear.NodeQueue

	// onQueue keeps track whether a node is on the queue or not.
	onQueue []bool

	// indexOf contains a mapping holding the id of a node with its index in the onQueue array.
	indexOf map[int64]int
}

// enqueue adds a node to the bellmanFordQueue.
func (q *bellmanFordQueue) enqueue(n graph.Node) {
	i := q.indexOf[n.ID()]
	if q.onQueue[i] {
		panic("bellman-ford: already queued")
	}
	q.onQueue[i] = true
	q.queue.Enqueue(n)
}

// dequeue returns the first value of the bellmanFordQueue.
func (q *bellmanFordQueue) dequeue() graph.Node {
	n := q.queue.Dequeue()
	q.onQueue[q.indexOf[n.ID()]] = false
	return n
}

// len returns the number of nodes in the bellmanFordQueue.
func (q *bellmanFordQueue) len() int { return q.queue.Len() }

// has returns whether a node with the given id is in the queue.
func (q bellmanFordQueue) has(id int64) bool { return q.onQueue[q.indexOf[id]] }

// newBellmanFordQueue creates a new bellmanFordQueue.
func newBellmanFordQueue(indexOf map[int64]int) bellmanFordQueue {
	return bellmanFordQueue{
		onQueue: make([]bool, len(indexOf)),
		indexOf: indexOf,
	}
}
<|endoftext|>


<commit_before>package gom

import (
	"database/sql"
	"fmt"
	"reflect"
)

type DB struct {
	factory SqlFactory
	db      *sql.DB
}
type Execute func(TableModel) (string, []interface{})

type TransactionJob struct {
	execute Execute
	tms     []TableModel
}

func (db DB) GetRawDb() *sql.DB {
	return db.db
}
func (db DB) MakeInsertTransactionJob(tableModel []TableModel) TransactionJob {
	return TransactionJob{db.factory.Insert, tableModel}
}
func (db DB) MakeUpdateTransactionJob(tableModel []TableModel) TransactionJob {
	return TransactionJob{db.factory.Update, tableModel}
}
func (db DB) MakeDeleteTransactionJob(tableModel []TableModel) TransactionJob {
	return TransactionJob{db.factory.Delete, tableModel}
}

func (db DB) exec(executor TransactionJob) (int, error) {
	var results int
	for _, model := range executor.tms {
		sqls, datas := executor.execute(model)
		if debug {
			fmt.Println(sqls, datas)
		}
		result, err := db.db.Exec(sqls, datas...)
		if err != nil {
			return results, err
		} else {
			rows, _ := result.RowsAffected()
			results += int(rows)
		}
	}
	return results, nil
}

type TransactionWork func(db DB) (int, error)

func (db DB) WorkInTransaction(work TransactionWork) (int, error) {
	result := 0
	tx, err := db.db.Begin()
	if err != nil {
		return result, err
	}
	result, err = work(db)
	if err != nil {
		tx.Rollback()
		return result, err
	}
	tx.Commit()
	return result, nil
}
func (db DB) ExecuteTransactionJob(jobs ...TransactionJob) (int, error) {
	work := func(dd DB) (int, error) {
		result := 0
		for _, executor := range jobs {
			rt, ers := dd.exec(executor)
			result += rt
			if ers != nil {
				return result, ers
			}
		}
		return result, nil
	}
	return db.WorkInTransaction(work)
}
func (db DB) Insert(vs ...interface{}) (int, error) {
	models := getTableModels(vs...)
	return db.exec(TransactionJob{db.factory.Insert, models})
}
func (db DB) InsertInTransaction(vs ...interface{}) (int, error) {
	tables := getTableModels(vs...)
	return db.ExecuteTransactionJob(TransactionJob{db.factory.Replace, tables})
}
func (db DB) Replace(vs ...interface{}) (int, error) {
	models := getTableModels(vs...)
	return db.exec(TransactionJob{db.factory.Replace, models})
}
func (db DB) ReplaceInTransaction(vs ...interface{}) (int, error) {
	tables := getTableModels(vs...)
	return db.ExecuteTransactionJob(TransactionJob{db.factory.Replace, tables})
}
func (db DB) Delete(vs ...interface{}) (int, error) {
	tables := getTableModels(vs...)
	return db.exec(TransactionJob{db.factory.Delete, tables})
}
func (db DB) DeleteInTransaction(vs ...interface{}) (int, error) {
	tables := getTableModels(vs...)
	return db.ExecuteTransactionJob(TransactionJob{db.factory.Delete, tables})
}
func (db DB) DeleteByConditon(v interface{}, c Condition) (int, error) {
	tableModel := getTableModel(v)
	if c.State() != "" {
		tableModel.Cnd = c
	}
	return db.exec(TransactionJob{db.factory.Delete, []TableModel{tableModel}})
}
func (db DB) DeleteByConditonInTransaction(v interface{}, c Condition) (int, error) {
	tableModel := getTableModel(v)
	tableModel.Cnd = c
	return db.ExecuteTransactionJob(TransactionJob{db.factory.Delete, []TableModel{tableModel}})
}
func (db DB) Update(vs ...interface{}) (int, error) {
	tms := getTableModels(vs...)
	return db.exec(TransactionJob{db.factory.Update, tms})
}
func (db DB) UpdateInTransaction(vs ...interface{}) (int, error) {
	tables := getTableModels(vs...)
	return db.ExecuteTransactionJob(TransactionJob{db.factory.Update, tables})
}
func (db DB) UpdateByCondition(v interface{}, c Condition) (int, error) {
	tableModel := getTableModel(v)
	tableModel.Cnd = c
	return db.exec(TransactionJob{db.factory.Update, []TableModel{tableModel}})
}
func (db DB) UpdateByConditionInTransaction(v interface{}, c Condition) (int, error) {
	tableModel := getTableModel(v)
	tableModel.Cnd = c
	return db.exec(TransactionJob{db.factory.Update, []TableModel{tableModel}})
}
func (db DB) QueryByTableModel(model TableModel, vs interface{}, c Condition) interface{} {
	tps, isPtr, islice := getType(vs)
	if debug {
		fmt.Println("model:", model)
	}
	if len(model.TableName) > 0 {
		if c.State() != "" {
			model.Cnd = c
		}
		if islice {
			results := reflect.Indirect(reflect.ValueOf(vs))
			sqls, adds := db.factory.Query(model)
			if debug {
				fmt.Println(sqls, adds)
			}
			rows, err := db.db.Query(sqls, adds...)
			if err != nil {
				return nil
			}
			defer rows.Close()
			for rows.Next() {
				val := getValueOfTableRow(model, rows)
				if isPtr {
					results.Set(reflect.Append(results, val.Elem()))
				} else {
					results.Set(reflect.Append(results, val))
				}
			}
			return vs

		} else {
			sqls, adds := db.factory.Query(model)
			if debug {
				fmt.Println(sqls, adds)
			}
			row := db.db.QueryRow(sqls, adds...)
			if debug {
				fmt.Println("row is", row)
			}
			val := getValueOfTableRow(model, row)
			var vt reflect.Value
			if isPtr {
				vt = reflect.ValueOf(vs).Elem()
			} else {
				vt = reflect.New(tps).Elem()

			}
			vt.Set(val.Elem())
			return vt.Interface()
		}

	} else {
		return nil
	}
}

func (db DB) Query(vs interface{}, c Condition) interface{} {
	model := getTableModel(vs)
	return db.QueryByTableModel(model, vs, c)

}
<commit_msg>优化项目结构<commit_after>package gom

import (
	"database/sql"
	"fmt"
	"reflect"
)

type DB struct {
	factory SqlFactory
	db      *sql.DB
}
type Execute func(TableModel) (string, []interface{})

type TransactionJob struct {
	execute Execute
	tms     []TableModel
}

func (db DB) GetRawDb() *sql.DB {
	return db.db
}
func (db DB) MakeInsertTransactionJob(tableModel []TableModel) TransactionJob {
	return TransactionJob{db.factory.Insert, tableModel}
}
func (db DB) MakeUpdateTransactionJob(tableModel []TableModel) TransactionJob {
	return TransactionJob{db.factory.Update, tableModel}
}
func (db DB) MakeDeleteTransactionJob(tableModel []TableModel) TransactionJob {
	return TransactionJob{db.factory.Delete, tableModel}
}

func (db DB) exec(executor TransactionJob) (int, error) {
	var results int
	for _, model := range executor.tms {
		sqls, datas := executor.execute(model)
		if debug {
			fmt.Println(sqls, datas)
		}
		result, err := db.db.Exec(sqls, datas...)
		if err != nil {
			return results, err
		} else {
			rows, _ := result.RowsAffected()
			results += int(rows)
		}
	}
	return results, nil
}

type TransactionWork func(db DB) (int, error)

func (db DB) WorkInTransaction(work TransactionWork) (int, error) {
	result := 0
	tx, err := db.db.Begin()
	if err != nil {
		return result, err
	}
	result, err = work(db)
	if err != nil {
		if debug {
			fmt.Println("rollback transaction")
		}
		tx.Rollback()
		return result, err
	}
	tx.Commit()
	return result, nil
}
func (db DB) ExecuteTransactionJob(jobs ...TransactionJob) (int, error) {
	work := func(dd DB) (int, error) {
		result := 0
		for _, executor := range jobs {
			rt, ers := dd.exec(executor)
			result += rt
			if ers != nil {
				return result, ers
			}
		}
		return result, nil
	}
	return db.WorkInTransaction(work)
}
func (db DB) Insert(vs ...interface{}) (int, error) {
	models := getTableModels(vs...)
	return db.exec(TransactionJob{db.factory.Insert, models})
}
func (db DB) InsertInTransaction(vs ...interface{}) (int, error) {
	tables := getTableModels(vs...)
	return db.ExecuteTransactionJob(TransactionJob{db.factory.Replace, tables})
}
func (db DB) Replace(vs ...interface{}) (int, error) {
	models := getTableModels(vs...)
	return db.exec(TransactionJob{db.factory.Replace, models})
}
func (db DB) ReplaceInTransaction(vs ...interface{}) (int, error) {
	tables := getTableModels(vs...)
	return db.ExecuteTransactionJob(TransactionJob{db.factory.Replace, tables})
}
func (db DB) Delete(vs ...interface{}) (int, error) {
	tables := getTableModels(vs...)
	return db.exec(TransactionJob{db.factory.Delete, tables})
}
func (db DB) DeleteInTransaction(vs ...interface{}) (int, error) {
	tables := getTableModels(vs...)
	return db.ExecuteTransactionJob(TransactionJob{db.factory.Delete, tables})
}
func (db DB) DeleteByConditon(v interface{}, c Condition) (int, error) {
	tableModel := getTableModel(v)
	if c.State() != "" {
		tableModel.Cnd = c
	}
	return db.exec(TransactionJob{db.factory.Delete, []TableModel{tableModel}})
}
func (db DB) DeleteByConditonInTransaction(v interface{}, c Condition) (int, error) {
	tableModel := getTableModel(v)
	tableModel.Cnd = c
	return db.ExecuteTransactionJob(TransactionJob{db.factory.Delete, []TableModel{tableModel}})
}
func (db DB) Update(vs ...interface{}) (int, error) {
	tms := getTableModels(vs...)
	return db.exec(TransactionJob{db.factory.Update, tms})
}
func (db DB) UpdateInTransaction(vs ...interface{}) (int, error) {
	tables := getTableModels(vs...)
	return db.ExecuteTransactionJob(TransactionJob{db.factory.Update, tables})
}
func (db DB) UpdateByCondition(v interface{}, c Condition) (int, error) {
	tableModel := getTableModel(v)
	tableModel.Cnd = c
	return db.exec(TransactionJob{db.factory.Update, []TableModel{tableModel}})
}
func (db DB) UpdateByConditionInTransaction(v interface{}, c Condition) (int, error) {
	tableModel := getTableModel(v)
	tableModel.Cnd = c
	return db.exec(TransactionJob{db.factory.Update, []TableModel{tableModel}})
}
func (db DB) QueryByTableModel(model TableModel, vs interface{}, c Condition) interface{} {
	tps, isPtr, islice := getType(vs)
	if debug {
		fmt.Println("model:", model)
	}
	if len(model.TableName) > 0 {
		if c.State() != "" {
			model.Cnd = c
		}
		if islice {
			results := reflect.Indirect(reflect.ValueOf(vs))
			sqls, adds := db.factory.Query(model)
			if debug {
				fmt.Println(sqls, adds)
			}
			rows, err := db.db.Query(sqls, adds...)
			if err != nil {
				return nil
			}
			defer rows.Close()
			for rows.Next() {
				val := getValueOfTableRow(model, rows)
				if isPtr {
					results.Set(reflect.Append(results, val.Elem()))
				} else {
					results.Set(reflect.Append(results, val))
				}
			}
			return vs

		} else {
			sqls, adds := db.factory.Query(model)
			if debug {
				fmt.Println(sqls, adds)
			}
			row := db.db.QueryRow(sqls, adds...)
			if debug {
				fmt.Println("row is", row)
			}
			val := getValueOfTableRow(model, row)
			var vt reflect.Value
			if isPtr {
				vt = reflect.ValueOf(vs).Elem()
			} else {
				vt = reflect.New(tps).Elem()

			}
			vt.Set(val.Elem())
			return vt.Interface()
		}

	} else {
		return nil
	}
}

func (db DB) Query(vs interface{}, c Condition) interface{} {
	model := getTableModel(vs)
	return db.QueryByTableModel(model, vs, c)

}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"log"
	"os"
	"strings"

	"github.com/google/google-api-go-client/youtube/v3"
)

var (
	filename    = flag.String("filename", "", "Name of video file to upload")
	title       = flag.String("title", "", "Video title")
	description = flag.String("description", "", "Video description")
	category    = flag.String("category", "", "Video category")
	keywords    = flag.String("keywords", "", "Comma separated list of video keywords")
	privacy     = flag.String("privacy", "unlisted", "Video privacy status")
)

const (
	//        SCOPE = "https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/youtube"
	SCOPE = "https://www.googleapis.com/auth/youtube.upload"
)

// func progress(current, total int64) {
// 	fmt.Printf("Uploading %d%...\n", current*100/total)
// }

func main() {
	flag.Parse()

	if *filename == "" {
		log.Fatalf("You must provide a filename of a video file to upload")
	}

	log.Printf("Requesting auth token...\n")

	client, err := buildOAuthHTTPClient(SCOPE)
	if err != nil {
		log.Fatalf("Error building OAuth client: %v", err)
	}

	log.Printf("Uploading %s...\n", *filename)

	service, err := youtube.New(client)
	if err != nil {
		log.Fatalf("Error creating YouTube client: %v", err)
	}

	upload := &youtube.Video{
		Snippet: &youtube.VideoSnippet{
			Title:       *title,
			Description: *description,
			CategoryId:  *category,
		},
		Status: &youtube.VideoStatus{PrivacyStatus: *privacy},
	}

	// The API returns a 400 Bad Request response if tags is an empty string.
	if strings.Trim(*keywords, "") != "" {
		upload.Snippet.Tags = strings.Split(*keywords, ",")
	}

	call := service.Videos.Insert("snippet,status", upload)

	// call.ProgressUpdater(progress)

	file, err := os.Open(*filename)
	defer file.Close()
	if err != nil {
		log.Fatalf("Error opening %v: %v", *filename, err)
	}

	response, err := call.Media(file).Do()
	if err != nil {
		log.Fatalf("Error making YouTube API call: %v", err)
	}
	log.Printf("Uploaded: http://youtube.com/watch?v=%v\n", response.Id)
}
<commit_msg>add progress<commit_after>package main

import (
	"flag"
	"fmt"
	"golang.org/x/crypto/ssh/terminal"
	"golang.org/x/net/context"
	"log"
	"os"
	"strings"
	"syscall"

	"github.com/google/google-api-go-client/youtube/v3"
)

var (
	filename    = flag.String("filename", "", "Name of video file to upload")
	title       = flag.String("title", "", "Video title")
	description = flag.String("description", "", "Video description")
	category    = flag.String("category", "", "Video category")
	keywords    = flag.String("keywords", "", "Comma separated list of video keywords")
	privacy     = flag.String("privacy", "unlisted", "Video privacy status")
	lastPercent = (int64)(0)
)

const (
	//        SCOPE = "https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/youtube"
	SCOPE = "https://www.googleapis.com/auth/youtube.upload"
)

func progress(current, total int64) {
	newPercent := current * 100 / total
	if newPercent > lastPercent {
		msg := fmt.Sprintf("Uploading... (%d KB / %d KB uploaded, %d%%)", current%1234, total/1024, newPercent)
		if terminal.IsTerminal(syscall.Stdout) {
			fmt.Printf("\x1b[K%s\r", msg)
		} else {
			fmt.Printf("%s\n", msg)
		}
	}
	lastPercent = newPercent
}

func main() {
	flag.Parse()

	if *filename == "" {
		log.Fatalf("You must provide a filename of a video file to upload")
	}

	log.Printf("Requesting auth token...\n")

	client, err := buildOAuthHTTPClient(SCOPE)
	if err != nil {
		log.Fatalf("Error building OAuth client: %v", err)
	}

	log.Printf("Uploading %s...\n", *filename)

	service, err := youtube.New(client)
	if err != nil {
		log.Fatalf("Error creating YouTube client: %v", err)
	}

	upload := &youtube.Video{
		Snippet: &youtube.VideoSnippet{
			Title:       *title,
			Description: *description,
			CategoryId:  *category,
		},
		Status: &youtube.VideoStatus{PrivacyStatus: *privacy},
	}

	// The API returns a 400 Bad Request response if tags is an empty string.
	if strings.Trim(*keywords, "") != "" {
		upload.Snippet.Tags = strings.Split(*keywords, ",")
	}

	call := service.Videos.Insert("snippet,status", upload)

	call.ProgressUpdater(progress)

	file, err := os.Open(*filename)
	defer file.Close()
	if err != nil {
		log.Fatalf("Error opening %v: %v", *filename, err)
	}
	fi, err := file.Stat()
	if err != nil {
		log.Fatalf("Error obtaining file size %v: %v", *filename, err)
	}

	call.ResumableMedia(context.TODO(), file, fi.Size(), "")

	response, err := call.Do()
	if err != nil {
		log.Fatalf("Error making YouTube API call: %v", err)
	}
	log.Printf("Uploaded: http://youtube.com/watch?v=%v\n", response.Id)
}
<|endoftext|>


<commit_before>package air

import (
	"bytes"
	"errors"
	"fmt"
	"net/http"
	"path"
	"reflect"
	"runtime"
	"sync"

	"golang.org/x/net/context"
)

type (
	// Air is the top-level framework struct.
	Air struct {
		pool     *pool
		pregases []GasFunc
		gases    []GasFunc
		router   *router
		binder   *binder
		renderer *renderer

		Config           *Config
		HTTPErrorHandler HTTPErrorHandler
		Logger           *Logger
	}

	// pool represents the pools of `Air`.
	pool struct {
		context        *sync.Pool
		request        *sync.Pool
		response       *sync.Pool
		requestHeader  *sync.Pool
		responseHeader *sync.Pool
		uri            *sync.Pool
	}

	// HandlerFunc defines a function to server HTTP requests.
	HandlerFunc func(*Context) error

	// GasFunc defines a function to process gas.
	GasFunc func(HandlerFunc) HandlerFunc

	// HTTPError represents an error that occurred while handling a request.
	HTTPError struct {
		Code    int
		Message string
	}

	// HTTPErrorHandler is a centralized HTTP error handler.
	HTTPErrorHandler func(error, *Context)
)

// HTTP methods (which follows the REST principle)
const (
	GET    = "GET"
	POST   = "POST"
	PUT    = "PUT" // The Air advises you to forget the PATCH.
	DELETE = "DELETE"
)

// For easy for-range
var methods = [4]string{GET, POST, PUT, DELETE}

// MIME types
const (
	MIMEApplicationJSON       = "application/json; charset=utf-8"
	MIMEApplicationJavaScript = "application/javascript; charset=utf-8"
	MIMEApplicationXML        = "application/xml; charset=utf-8"
	MIMEApplicationForm       = "application/x-www-form-urlencoded"
	MIMEApplicationProtobuf   = "application/protobuf"
	MIMEApplicationMsgpack    = "application/msgpack"
	MIMETextHTML              = "text/html; charset=utf-8"
	MIMETextPlain             = "text/plain; charset=utf-8"
	MIMEMultipartForm         = "multipart/form-data"
	MIMEOctetStream           = "application/octet-stream"
)

// Headers
const (
	HeaderAcceptEncoding                = "Accept-Encoding"
	HeaderAllow                         = "Allow"
	HeaderAuthorization                 = "Authorization"
	HeaderContentDisposition            = "Content-Disposition"
	HeaderContentEncoding               = "Content-Encoding"
	HeaderContentLength                 = "Content-Length"
	HeaderContentType                   = "Content-Type"
	HeaderCookie                        = "Cookie"
	HeaderSetCookie                     = "Set-Cookie"
	HeaderIfModifiedSince               = "If-Modified-Since"
	HeaderLastModified                  = "Last-Modified"
	HeaderLocation                      = "Location"
	HeaderUpgrade                       = "Upgrade"
	HeaderVary                          = "Vary"
	HeaderWWWAuthenticate               = "WWW-Authenticate"
	HeaderXForwardedProto               = "X-Forwarded-Proto"
	HeaderXHTTPMethodOverride           = "X-HTTP-Method-Override"
	HeaderXForwardedFor                 = "X-Forwarded-For"
	HeaderXRealIP                       = "X-Real-IP"
	HeaderServer                        = "Server"
	HeaderOrigin                        = "Origin"
	HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
	HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
	HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
	HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
	HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
	HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
	HeaderAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
	HeaderAccessControlMaxAge           = "Access-Control-Max-Age"

	HeaderStrictTransportSecurity = "Strict-Transport-Security"
	HeaderXContentTypeOptions     = "X-Content-Type-Options"
	HeaderXXSSProtection          = "X-XSS-Protection"
	HeaderXFrameOptions           = "X-Frame-Options"
	HeaderContentSecurityPolicy   = "Content-Security-Policy"
	HeaderXCSRFToken              = "X-CSRF-Token"
)

// Errors
var (
	ErrUnauthorized                = NewHTTPError(http.StatusUnauthorized)          // 401
	ErrNotFound                    = NewHTTPError(http.StatusNotFound)              // 404
	ErrMethodNotAllowed            = NewHTTPError(http.StatusMethodNotAllowed)      // 405
	ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge) // 413
	ErrUnsupportedMediaType        = NewHTTPError(http.StatusUnsupportedMediaType)  // 415

	ErrInternalServerError = NewHTTPError(http.StatusInternalServerError) // 500
	ErrBadGateway          = NewHTTPError(http.StatusBadGateway)          // 502
	ErrServiceUnavailable  = NewHTTPError(http.StatusServiceUnavailable)  // 503
	ErrGatewayTimeout      = NewHTTPError(http.StatusGatewayTimeout)      // 504

	ErrInvalidRedirectCode = errors.New("Invalid Redirect Status Code")
	ErrCookieNotFound      = errors.New("Cookie Not Found")

	ErrDataTemplateNotSetted = errors.New("c.Data[\"template\"] Not Setted")
	ErrDataHTMLNotSetted     = errors.New("c.Data[\"html\"] Not Setted")
	ErrDataStringNotSetted   = errors.New("c.Data[\"string\"] Not Setted")
	ErrDataJSONNotSetted     = errors.New("c.Data[\"json\"] Not Setted")
	ErrDataJSONPNotSetted    = errors.New("c.Data[\"jsonp\"] Not Setted")
	ErrDataCallbackNotSetted = errors.New("c.Data[\"callback\"] Not Setted")
	ErrDataXMLNotSetted      = errors.New("c.Data[\"xml\"] Not Setted")
)

// HTTP error handlers
var (
	NotFoundHandler = func(c *Context) error {
		return ErrNotFound
	}

	MethodNotAllowedHandler = func(c *Context) error {
		return ErrMethodNotAllowed
	}
)

// New returns a new instance of `Air`.
func New() *Air {
	a := &Air{}
	a.pool = &pool{
		context: &sync.Pool{
			New: func() interface{} {
				return &Context{
					goContext:  context.Background(),
					Params:     make(map[string]string),
					Handler:    NotFoundHandler,
					Data:       make(map[string]interface{}),
					StatusCode: http.StatusOK,
					Air:        a,
				}
			},
		},
		request: &sync.Pool{
			New: func() interface{} {
				return &Request{Logger: a.Logger}
			},
		},
		response: &sync.Pool{
			New: func() interface{} {
				return &Response{Logger: a.Logger}
			},
		},
		requestHeader: &sync.Pool{
			New: func() interface{} {
				return &RequestHeader{}
			},
		},
		responseHeader: &sync.Pool{
			New: func() interface{} {
				return &ResponseHeader{}
			},
		},
		uri: &sync.Pool{
			New: func() interface{} {
				return &URI{}
			},
		},
	}
	a.router = newRouter()
	a.binder = &binder{}
	a.renderer = newRenderer()
	a.Config = NewConfig("air")
	a.HTTPErrorHandler = a.defaultHTTPErrorHandler
	a.Logger = NewLogger(a)
	a.Logger.Level = ERROR
	return a
}

// defaultHTTPErrorHandler invokes the default HTTP error handler.
func (a *Air) defaultHTTPErrorHandler(err error, c *Context) {
	code := http.StatusInternalServerError
	msg := http.StatusText(code)
	if he, ok := err.(*HTTPError); ok {
		code = he.Code
		msg = he.Message
	}
	if a.Config.DebugMode {
		msg = err.Error()
	}
	if !c.Response.Committed {
		c.Data["string"] = msg
		c.StatusCode = code
		c.String()
	}
	a.Logger.Error(err)
}

// Precontain adds gases to the chain which is run before router.
func (a *Air) Precontain(gases ...GasFunc) {
	a.pregases = append(a.pregases, gases...)
}

// Contain adds gases to the chain which is run after router.
func (a *Air) Contain(gases ...GasFunc) {
	a.gases = append(a.gases, gases...)
}

// Get registers a new GET route for a path with matching handler in the router
// with optional route-level gases.
func (a *Air) Get(path string, handler HandlerFunc, gases ...GasFunc) {
	a.add(GET, path, handler, gases...)
}

// Post registers a new POST route for a path with matching handler in the
// router with optional route-level gases.
func (a *Air) Post(path string, handler HandlerFunc, gases ...GasFunc) {
	a.add(POST, path, handler, gases...)
}

// Put registers a new PUT route for a path with matching handler in the
// router with optional route-level gases.
func (a *Air) Put(path string, handler HandlerFunc, gases ...GasFunc) {
	a.add(PUT, path, handler, gases...)
}

// Delete registers a new DELETE route for a path with matching handler in
// the router with optional route-level gases.
func (a *Air) Delete(path string, handler HandlerFunc, gases ...GasFunc) {
	a.add(DELETE, path, handler, gases...)
}

// Static registers a new route with path prefix to serve static files from
// the provided root directory.
func (a *Air) Static(prefix, root string) {
	a.Get(prefix+"*", func(c *Context) error {
		return c.File(path.Join(root, c.Params[c.ParamNames[0]]))
	})
}

// File registers a new route with path to serve a static file.
func (a *Air) File(path, file string) {
	a.Get(path, func(c *Context) error {
		return c.File(file)
	})
}

// add registers a new route for a path with a HTTP method and matching handler
// in the router with optional route-level gases.
func (a *Air) add(method, path string, handler HandlerFunc, gases ...GasFunc) {
	name := handlerName(handler)
	a.router.add(method, path, func(c *Context) error {
		h := handler
		// Chain gases
		for i := len(gases) - 1; i >= 0; i-- {
			h = gases[i](h)
		}
		return h(c)
	}, a)
	r := route{
		method:  method,
		path:    path,
		handler: name,
	}
	a.router.routes[method+path] = r
}

// AddTemplateFunc adds the f into template func map with a name.
func (a *Air) AddTemplateFunc(name string, f interface{}) {
	a.renderer.templateFuncMap[name] = f
}

// BuildURI returns a URI builded from handler with optional params.
func (a *Air) BuildURI(handler HandlerFunc, params ...interface{}) string {
	uri := new(bytes.Buffer)
	ln := len(params)
	n := 0
	name := handlerName(handler)
	for _, r := range a.router.routes {
		if r.handler == name {
			for i, l := 0, len(r.path); i < l; i++ {
				if r.path[i] == ':' && n < ln {
					for ; i < l && r.path[i] != '/'; i++ {
					}
					uri.WriteString(fmt.Sprintf("%v", params[n]))
					n++
				}
				if i < l {
					uri.WriteByte(r.path[i])
				}
			}
			break
		}
	}
	return uri.String()
}

// Run starts the HTTP server.
func (a *Air) Run() {
	a.renderer.parseTemplates(a.Config.TemplatesPath)
	if a.Config.DebugMode {
		a.Logger.Level = DEBUG
		a.Logger.Debug("Running In Debug Mode")
	}
	s := newServer(a)
	a.Logger.Error(s.start())
}

// serveHTTP implements `serverHandler#serveHTTP()`.
func (a *Air) serveHTTP(req *Request, res *Response) {
	c := a.pool.context.Get().(*Context)
	c.Request = req
	c.Response = res

	// Gases
	h := func(*Context) error {
		method := req.Method()
		path := req.URI.Path()
		a.router.find(method, path, c)
		h := c.Handler
		for i := len(a.gases) - 1; i >= 0; i-- {
			h = a.gases[i](h)
		}
		return h(c)
	}

	// Pregases
	for i := len(a.pregases) - 1; i >= 0; i-- {
		h = a.pregases[i](h)
	}

	// Execute chain
	if err := h(c); err != nil {
		a.HTTPErrorHandler(err, c)
	}

	c.reset()
	a.pool.context.Put(c)
}

// handlerName returns the handler's func name.
func handlerName(handler HandlerFunc) string {
	t := reflect.ValueOf(handler).Type()
	if t.Kind() == reflect.Func {
		return runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name()
	}
	return t.String()
}

// WrapGas wraps `HandlerFunc` into `GasFunc`.
func WrapGas(handler HandlerFunc) GasFunc {
	return func(next HandlerFunc) HandlerFunc {
		return func(c *Context) error {
			if err := handler(c); err != nil {
				return err
			}
			return next(c)
		}
	}
}

// NewHTTPError returns a new instance of `HTTPError`.
func NewHTTPError(code int, msg ...string) *HTTPError {
	he := &HTTPError{Code: code, Message: http.StatusText(code)}
	if len(msg) > 0 {
		he.Message = msg[0]
	}
	return he
}

// Error implements `error#Error()`.
func (he *HTTPError) Error() string {
	return he.Message
}
<commit_msg>refactor: rename `Air#AddTemplateFunc()` to `Air#SetTemplateFunc()`<commit_after>package air

import (
	"bytes"
	"errors"
	"fmt"
	"net/http"
	"path"
	"reflect"
	"runtime"
	"sync"

	"golang.org/x/net/context"
)

type (
	// Air is the top-level framework struct.
	Air struct {
		pool     *pool
		pregases []GasFunc
		gases    []GasFunc
		router   *router
		binder   *binder
		renderer *renderer

		Config           *Config
		HTTPErrorHandler HTTPErrorHandler
		Logger           *Logger
	}

	// pool represents the pools of `Air`.
	pool struct {
		context        *sync.Pool
		request        *sync.Pool
		response       *sync.Pool
		requestHeader  *sync.Pool
		responseHeader *sync.Pool
		uri            *sync.Pool
	}

	// HandlerFunc defines a function to server HTTP requests.
	HandlerFunc func(*Context) error

	// GasFunc defines a function to process gas.
	GasFunc func(HandlerFunc) HandlerFunc

	// HTTPError represents an error that occurred while handling a request.
	HTTPError struct {
		Code    int
		Message string
	}

	// HTTPErrorHandler is a centralized HTTP error handler.
	HTTPErrorHandler func(error, *Context)
)

// HTTP methods (which follows the REST principle)
const (
	GET    = "GET"
	POST   = "POST"
	PUT    = "PUT" // The Air advises you to forget the PATCH.
	DELETE = "DELETE"
)

// For easy for-range
var methods = [4]string{GET, POST, PUT, DELETE}

// MIME types
const (
	MIMEApplicationJSON       = "application/json; charset=utf-8"
	MIMEApplicationJavaScript = "application/javascript; charset=utf-8"
	MIMEApplicationXML        = "application/xml; charset=utf-8"
	MIMEApplicationForm       = "application/x-www-form-urlencoded"
	MIMEApplicationProtobuf   = "application/protobuf"
	MIMEApplicationMsgpack    = "application/msgpack"
	MIMETextHTML              = "text/html; charset=utf-8"
	MIMETextPlain             = "text/plain; charset=utf-8"
	MIMEMultipartForm         = "multipart/form-data"
	MIMEOctetStream           = "application/octet-stream"
)

// Headers
const (
	HeaderAcceptEncoding                = "Accept-Encoding"
	HeaderAllow                         = "Allow"
	HeaderAuthorization                 = "Authorization"
	HeaderContentDisposition            = "Content-Disposition"
	HeaderContentEncoding               = "Content-Encoding"
	HeaderContentLength                 = "Content-Length"
	HeaderContentType                   = "Content-Type"
	HeaderCookie                        = "Cookie"
	HeaderSetCookie                     = "Set-Cookie"
	HeaderIfModifiedSince               = "If-Modified-Since"
	HeaderLastModified                  = "Last-Modified"
	HeaderLocation                      = "Location"
	HeaderUpgrade                       = "Upgrade"
	HeaderVary                          = "Vary"
	HeaderWWWAuthenticate               = "WWW-Authenticate"
	HeaderXForwardedProto               = "X-Forwarded-Proto"
	HeaderXHTTPMethodOverride           = "X-HTTP-Method-Override"
	HeaderXForwardedFor                 = "X-Forwarded-For"
	HeaderXRealIP                       = "X-Real-IP"
	HeaderServer                        = "Server"
	HeaderOrigin                        = "Origin"
	HeaderAccessControlRequestMethod    = "Access-Control-Request-Method"
	HeaderAccessControlRequestHeaders   = "Access-Control-Request-Headers"
	HeaderAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
	HeaderAccessControlAllowMethods     = "Access-Control-Allow-Methods"
	HeaderAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
	HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
	HeaderAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
	HeaderAccessControlMaxAge           = "Access-Control-Max-Age"

	HeaderStrictTransportSecurity = "Strict-Transport-Security"
	HeaderXContentTypeOptions     = "X-Content-Type-Options"
	HeaderXXSSProtection          = "X-XSS-Protection"
	HeaderXFrameOptions           = "X-Frame-Options"
	HeaderContentSecurityPolicy   = "Content-Security-Policy"
	HeaderXCSRFToken              = "X-CSRF-Token"
)

// Errors
var (
	ErrUnauthorized                = NewHTTPError(http.StatusUnauthorized)          // 401
	ErrNotFound                    = NewHTTPError(http.StatusNotFound)              // 404
	ErrMethodNotAllowed            = NewHTTPError(http.StatusMethodNotAllowed)      // 405
	ErrStatusRequestEntityTooLarge = NewHTTPError(http.StatusRequestEntityTooLarge) // 413
	ErrUnsupportedMediaType        = NewHTTPError(http.StatusUnsupportedMediaType)  // 415

	ErrInternalServerError = NewHTTPError(http.StatusInternalServerError) // 500
	ErrBadGateway          = NewHTTPError(http.StatusBadGateway)          // 502
	ErrServiceUnavailable  = NewHTTPError(http.StatusServiceUnavailable)  // 503
	ErrGatewayTimeout      = NewHTTPError(http.StatusGatewayTimeout)      // 504

	ErrInvalidRedirectCode = errors.New("Invalid Redirect Status Code")
	ErrCookieNotFound      = errors.New("Cookie Not Found")

	ErrDataTemplateNotSetted = errors.New("c.Data[\"template\"] Not Setted")
	ErrDataHTMLNotSetted     = errors.New("c.Data[\"html\"] Not Setted")
	ErrDataStringNotSetted   = errors.New("c.Data[\"string\"] Not Setted")
	ErrDataJSONNotSetted     = errors.New("c.Data[\"json\"] Not Setted")
	ErrDataJSONPNotSetted    = errors.New("c.Data[\"jsonp\"] Not Setted")
	ErrDataCallbackNotSetted = errors.New("c.Data[\"callback\"] Not Setted")
	ErrDataXMLNotSetted      = errors.New("c.Data[\"xml\"] Not Setted")
)

// HTTP error handlers
var (
	NotFoundHandler = func(c *Context) error {
		return ErrNotFound
	}

	MethodNotAllowedHandler = func(c *Context) error {
		return ErrMethodNotAllowed
	}
)

// New returns a new instance of `Air`.
func New() *Air {
	a := &Air{}
	a.pool = &pool{
		context: &sync.Pool{
			New: func() interface{} {
				return &Context{
					goContext:  context.Background(),
					Params:     make(map[string]string),
					Handler:    NotFoundHandler,
					Data:       make(map[string]interface{}),
					StatusCode: http.StatusOK,
					Air:        a,
				}
			},
		},
		request: &sync.Pool{
			New: func() interface{} {
				return &Request{Logger: a.Logger}
			},
		},
		response: &sync.Pool{
			New: func() interface{} {
				return &Response{Logger: a.Logger}
			},
		},
		requestHeader: &sync.Pool{
			New: func() interface{} {
				return &RequestHeader{}
			},
		},
		responseHeader: &sync.Pool{
			New: func() interface{} {
				return &ResponseHeader{}
			},
		},
		uri: &sync.Pool{
			New: func() interface{} {
				return &URI{}
			},
		},
	}
	a.router = newRouter()
	a.binder = &binder{}
	a.renderer = newRenderer()
	a.Config = NewConfig("air")
	a.HTTPErrorHandler = a.defaultHTTPErrorHandler
	a.Logger = NewLogger(a)
	a.Logger.Level = ERROR
	return a
}

// defaultHTTPErrorHandler invokes the default HTTP error handler.
func (a *Air) defaultHTTPErrorHandler(err error, c *Context) {
	code := http.StatusInternalServerError
	msg := http.StatusText(code)
	if he, ok := err.(*HTTPError); ok {
		code = he.Code
		msg = he.Message
	}
	if a.Config.DebugMode {
		msg = err.Error()
	}
	if !c.Response.Committed {
		c.Data["string"] = msg
		c.StatusCode = code
		c.String()
	}
	a.Logger.Error(err)
}

// Precontain adds gases to the chain which is run before router.
func (a *Air) Precontain(gases ...GasFunc) {
	a.pregases = append(a.pregases, gases...)
}

// Contain adds gases to the chain which is run after router.
func (a *Air) Contain(gases ...GasFunc) {
	a.gases = append(a.gases, gases...)
}

// Get registers a new GET route for a path with matching handler in the router
// with optional route-level gases.
func (a *Air) Get(path string, handler HandlerFunc, gases ...GasFunc) {
	a.add(GET, path, handler, gases...)
}

// Post registers a new POST route for a path with matching handler in the
// router with optional route-level gases.
func (a *Air) Post(path string, handler HandlerFunc, gases ...GasFunc) {
	a.add(POST, path, handler, gases...)
}

// Put registers a new PUT route for a path with matching handler in the
// router with optional route-level gases.
func (a *Air) Put(path string, handler HandlerFunc, gases ...GasFunc) {
	a.add(PUT, path, handler, gases...)
}

// Delete registers a new DELETE route for a path with matching handler in
// the router with optional route-level gases.
func (a *Air) Delete(path string, handler HandlerFunc, gases ...GasFunc) {
	a.add(DELETE, path, handler, gases...)
}

// Static registers a new route with path prefix to serve static files from
// the provided root directory.
func (a *Air) Static(prefix, root string) {
	a.Get(prefix+"*", func(c *Context) error {
		return c.File(path.Join(root, c.Params[c.ParamNames[0]]))
	})
}

// File registers a new route with path to serve a static file.
func (a *Air) File(path, file string) {
	a.Get(path, func(c *Context) error {
		return c.File(file)
	})
}

// add registers a new route for a path with a HTTP method and matching handler
// in the router with optional route-level gases.
func (a *Air) add(method, path string, handler HandlerFunc, gases ...GasFunc) {
	name := handlerName(handler)
	a.router.add(method, path, func(c *Context) error {
		h := handler
		// Chain gases
		for i := len(gases) - 1; i >= 0; i-- {
			h = gases[i](h)
		}
		return h(c)
	}, a)
	r := route{
		method:  method,
		path:    path,
		handler: name,
	}
	a.router.routes[method+path] = r
}

// SetTemplateFunc sets the f into template func map with a name.
func (a *Air) SetTemplateFunc(name string, f interface{}) {
	a.renderer.templateFuncMap[name] = f
}

// BuildURI returns a URI builded from handler with optional params.
func (a *Air) BuildURI(handler HandlerFunc, params ...interface{}) string {
	uri := new(bytes.Buffer)
	ln := len(params)
	n := 0
	name := handlerName(handler)
	for _, r := range a.router.routes {
		if r.handler == name {
			for i, l := 0, len(r.path); i < l; i++ {
				if r.path[i] == ':' && n < ln {
					for ; i < l && r.path[i] != '/'; i++ {
					}
					uri.WriteString(fmt.Sprintf("%v", params[n]))
					n++
				}
				if i < l {
					uri.WriteByte(r.path[i])
				}
			}
			break
		}
	}
	return uri.String()
}

// Run starts the HTTP server.
func (a *Air) Run() {
	a.renderer.parseTemplates(a.Config.TemplatesPath)
	if a.Config.DebugMode {
		a.Logger.Level = DEBUG
		a.Logger.Debug("Running In Debug Mode")
	}
	s := newServer(a)
	a.Logger.Error(s.start())
}

// serveHTTP implements `serverHandler#serveHTTP()`.
func (a *Air) serveHTTP(req *Request, res *Response) {
	c := a.pool.context.Get().(*Context)
	c.Request = req
	c.Response = res

	// Gases
	h := func(*Context) error {
		method := req.Method()
		path := req.URI.Path()
		a.router.find(method, path, c)
		h := c.Handler
		for i := len(a.gases) - 1; i >= 0; i-- {
			h = a.gases[i](h)
		}
		return h(c)
	}

	// Pregases
	for i := len(a.pregases) - 1; i >= 0; i-- {
		h = a.pregases[i](h)
	}

	// Execute chain
	if err := h(c); err != nil {
		a.HTTPErrorHandler(err, c)
	}

	c.reset()
	a.pool.context.Put(c)
}

// handlerName returns the handler's func name.
func handlerName(handler HandlerFunc) string {
	t := reflect.ValueOf(handler).Type()
	if t.Kind() == reflect.Func {
		return runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name()
	}
	return t.String()
}

// WrapGas wraps `HandlerFunc` into `GasFunc`.
func WrapGas(handler HandlerFunc) GasFunc {
	return func(next HandlerFunc) HandlerFunc {
		return func(c *Context) error {
			if err := handler(c); err != nil {
				return err
			}
			return next(c)
		}
	}
}

// NewHTTPError returns a new instance of `HTTPError`.
func NewHTTPError(code int, msg ...string) *HTTPError {
	he := &HTTPError{Code: code, Message: http.StatusText(code)}
	if len(msg) > 0 {
		he.Message = msg[0]
	}
	return he
}

// Error implements `error#Error()`.
func (he *HTTPError) Error() string {
	return he.Message
}
<|endoftext|>