<commit_before>// Package persist provides implementations for the domain repos
package persist

import (
	"entity"
	"errors"
	"fmt"
)

type PersistMem struct {
	Profiles  []*entity.Profile
	Questions []*entity.Question
	Reviews   []*entity.Review
}

func (self *PersistMem) GetAllProfiles() ([]*entity.Profile, error) {
	v := make([]*entity.Profile, 1)
	v[0] = &entity.Profile{
		Version: entity.Version{"pace", 1, 0, 0},
		Questions: []*entity.Question{
			&entity.Question{
				Version:     entity.Version{"who", 1, 0, 0},
				Text:        "Who?",
				Help:        "...'s on first?",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
		},
	}
	return v, nil
}

func (self *PersistMem) GetProfileById(version entity.Version) (*entity.Profile, error) {
	profiles, err := self.GetAllProfiles()
	if err != nil {
		return nil, err
	}
	for _, prof := range profiles {
		if prof.Version == version {
			return prof, nil
		}
	}
	return nil, errors.New(fmt.Sprintf("PersistMem.GetProfileById(): profile version '%v' not found", version))
}

func (self *PersistMem) GetAllQuestions() ([]*entity.Question, error) {
	v := make([]*entity.Question, 1)
	v[0] = &entity.Question{
		Version:     entity.Version{"who", 1, 0, 0},
		Text:        "Who?",
		Help:        "...'s on first?",
		AnswerType:  entity.ANSWER_TYPE_TEXT,
		DisplayHint: "",
	}
	return v, nil
}

func (self *PersistMem) GetQuestionById(version entity.Version) (*entity.Question, error) {
	return nil, errors.New("PersistMem.GetQuestionById not implemented")
}

func (self *PersistMem) GetAllReviews() ([]*entity.Review, error) {
	return self.Reviews, nil
}

func (self *PersistMem) GetReviewById(version entity.Version) (*entity.Review, error) {
	reviews, err := self.GetAllReviews()
	if err != nil {
		return nil, err
	}
	for _, rev := range reviews {
		if rev.Version == version {
			return rev, nil
		}
	}
	return nil, errors.New(fmt.Sprintf("PersistMem.GetReviewById(): review version '%v' not found", version))
}

func (self *PersistMem) AddReview(review *entity.Review) error {
	found := false
	for idx, rev := range self.Reviews {
		if rev.Version == review.Version {
			found = true
			self.Reviews[idx] = review
		}
	}
	if !found {
		self.Reviews = append(self.Reviews, review)
	}
	return nil
}
<commit_msg>Add more questions.<commit_after>// Package persist provides implementations for the domain repos
package persist

import (
	"entity"
	"errors"
	"fmt"
)

type PersistMem struct {
	Profiles  []*entity.Profile
	Questions []*entity.Question
	Reviews   []*entity.Review
}

func (self *PersistMem) GetAllProfiles() ([]*entity.Profile, error) {
	v := make([]*entity.Profile, 1)
	v[0] = &entity.Profile{
		Version: entity.Version{"pace", 1, 0, 0},
		Questions: []*entity.Question{
			&entity.Question{
				Version:     entity.Version{"agora-pages", 1, 0, 0},
				Text:        "Which agora pages describe your product?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"bart-releases", 1, 0, 0},
				Text:        "Which BART releases are you using?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"billing-method", 1, 0, 0},
				Text:        "What's your billing method?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"code-lines", 1, 0, 0},
				Text:        "What are your code lines?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"component-names", 1, 0, 0},
				Text:        "What are your components called?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"features", 1, 0, 0},
				Text:        "What features does your product build on?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"bugzilla-tickets", 1, 0, 0},
				Text:        "What CRs does your launch close?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"deployed-networks", 1, 0, 0},
				Text:        "What networks will you be deploying to?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"engineering-schedule-contact", 1, 0, 0},
				Text:        "Who can speak authoritatively about your engineering schedule?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"etherpad-links", 1, 0, 0},
				Text:        "Which etherpad should we use to collaborate on writing up your review?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"implementation-contact", 1, 0, 0},
				Text:        "Who can speak authoritatively about your product's technical implementation details?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"implementation-contact", 1, 0, 0},
				Text:        "Who can speak authoritatively about your product's technical implementation details?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"secarch-review-link", 1, 0, 0},
				Text:        "Which SecArch review covers your product?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"olympus-tickets", 1, 0, 0},
				Text:        "Which Olympus KFs does your product address?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"module-design-link", 1, 0, 0},
				Text:        "Where is your module design document?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"product-contacts", 1, 0, 0},
				Text:        "Who can speak authoritatively about your product's strategy, packaging, etc.",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"program-manager", 1, 0, 0},
				Text:        "Who is program-managing your product?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"secarch-advisor", 1, 0, 0},
				Text:        "Who from SecArch is advising you?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"secarch-reviewer", 1, 0, 0},
				Text:        "Who from SecArch is reviewing your product's security considerations?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"technical-design-contact", 1, 0, 0},
				Text:        "Who can speak authoritatively about your product's technical architecture and design?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
			&entity.Question{
				Version:     entity.Version{"jira-tickets", 1, 0, 0},
				Text:        "What Jira tickets does this launch or commit address?",
				Help:        "",
				AnswerType:  entity.ANSWER_TYPE_TEXT,
				DisplayHint: "",
			},
		},
	}
	return v, nil
}

func (self *PersistMem) GetProfileById(version entity.Version) (*entity.Profile, error) {
	profiles, err := self.GetAllProfiles()
	if err != nil {
		return nil, err
	}
	for _, prof := range profiles {
		if prof.Version == version {
			return prof, nil
		}
	}
	return nil, errors.New(fmt.Sprintf("PersistMem.GetProfileById(): profile version '%v' not found", version))
}

func (self *PersistMem) GetAllQuestions() ([]*entity.Question, error) {
	return nil, errors.New("PersistMem.GetAllQuestions() not implemented")
}

func (self *PersistMem) GetQuestionById(version entity.Version) (*entity.Question, error) {
	return nil, errors.New("PersistMem.GetQuestionById() not implemented")
}

func (self *PersistMem) GetAllReviews() ([]*entity.Review, error) {
	return self.Reviews, nil
}

func (self *PersistMem) GetReviewById(version entity.Version) (*entity.Review, error) {
	reviews, err := self.GetAllReviews()
	if err != nil {
		return nil, err
	}
	for _, rev := range reviews {
		if rev.Version == version {
			return rev, nil
		}
	}
	return nil, errors.New(fmt.Sprintf("PersistMem.GetReviewById(): review version '%v' not found", version))
}

func (self *PersistMem) AddReview(review *entity.Review) error {
	found := false
	for idx, rev := range self.Reviews {
		if rev.Version == review.Version {
			found = true
			self.Reviews[idx] = review
		}
	}
	if !found {
		self.Reviews = append(self.Reviews, review)
	}
	return nil
}
<|endoftext|>


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

// This file contains operations on unsigned multi-precision integers.
// These are the building blocks for the operations on signed integers
// and rationals.

// This package implements multi-precision arithmetic (big numbers).
// The following numeric types are supported:
//
//	- Int	signed integers
//
// All methods on Int take the result as the receiver; if it is one
// of the operands it may be overwritten (and its memory reused).
// To enable chaining of operations, the result is also returned.
//
package big

// An unsigned integer x of the form
//
//   x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0]
//
// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n,
// with the digits x[i] as the slice elements.
//
// A number is normalized if the slice contains no leading 0 digits.
// During arithmetic operations, denormalized values may occur but are
// always normalized before returning the final result. The normalized
// representation of 0 is the empty or nil slice (length = 0).

// TODO(gri) - convert these routines into methods for type 'nat'
//           - decide if type 'nat' should be exported

func normN(z []Word) []Word {
	i := len(z);
	for i > 0 && z[i-1] == 0 {
		i--;
	}
	z = z[0 : i];
	return z;
}

func makeN(z []Word, m int, clear bool) []Word {
	if len(z) > m {
		z = z[0 : m];  // reuse z - has at least one extra word for a carry, if any
		if clear {
			for i := range z {
				z[i] = 0;
			}
		}
		return z;
	}

	c := 4;  // minimum capacity
	if m > c {
		c = m;
	}
	return make([]Word, m, c+1);  // +1: extra word for a carry, if any
}

func newN(z []Word, x uint64) []Word {
	if x == 0 {
		return makeN(z, 0, false);
	}

	// single-digit values
	if x == uint64(Word(x)) {
		z = makeN(z, 1, false);
		z[0] = Word(x);
		return z;
	}

	// compute number of words n required to represent x
	n := 0;
	for t := x; t > 0; t >>= _W {
		n++;
	}

	// split x into n words
	z = makeN(z, n, false);
	for i := 0; i < n; i++ {
		z[i] = Word(x & _M);
		x >>= _W;
	}

	return z;
}

func setN(z, x []Word) []Word {
	z = makeN(z, len(x), false);
	for i, d := range x {
		z[i] = d;
	}
	return z;
}

func addNN(z, x, y []Word) []Word {
	m := len(x);
	n := len(y);

	switch {
	case m < n:
		return addNN(z, y, x);
	case m == 0:
		// n == 0 because m >= n; result is 0
		return makeN(z, 0, false);
	case n == 0:
		// result is x
		return setN(z, x);
	}
	// m > 0

	z = makeN(z, m, false);
	c := addVV(&z[0], &x[0], &y[0], n);
	if m > n {
		c = addVW(&z[n], &x[n], c, m-n);
	}
	if c > 0 {
		z = z[0 : m+1];
		z[m] = c;
	}

	return z;
}

func subNN(z, x, y []Word) []Word {
	m := len(x);
	n := len(y);

	switch {
	case m < n:
		panic("underflow");
	case m == 0:
		// n == 0 because m >= n; result is 0
		return makeN(z, 0, false);
	case n == 0:
		// result is x
		return setN(z, x);
	}
	// m > 0

	z = makeN(z, m, false);
	c := subVV(&z[0], &x[0], &y[0], n);
	if m > n {
		c = subVW(&z[n], &x[n], c, m-n);
	}
	if c != 0 {
		panic("underflow");
	}
	z = normN(z);

	return z;
}

func cmpNN(x, y []Word) (r int) {
	m := len(x);
	n := len(y);
	if m != n || m == 0 {
		switch {
		case m < n: r = -1;
		case m > n: r = 1;
		}
		return;
	}

	i := m-1;
	for i > 0 && x[i] == y[i] {
		i--;
	}

	switch {
	case x[i] < y[i]: r = -1;
	case x[i] > y[i]: r = 1;
	}
	return;
}

func mulAddNWW(z, x []Word, y, r Word) []Word {
	m := len(x);
	if m == 0 || y == 0 {
		return newN(z, uint64(r));	// result is r
	}
	// m > 0

	z = makeN(z, m, false);
	c := mulAddVWW(&z[0], &x[0], y, r, m);
	if c > 0 {
		z = z[0 : m+1];
		z[m] = c;
	}

	return z;
}

func mulNN(z, x, y []Word) []Word {
	m := len(x);
	n := len(y);

	switch {
	case m < n:
		return mulNN(z, y, x);
	case m == 0 || n == 0:
		return makeN(z, 0, false);
	case n == 1:
		return mulAddNWW(z, x, y[0], 0);
	}
	// m >= n && m > 1 && n > 1

	z = makeN(z, m+n, true);
	if &z[0] == &x[0] || &z[0] == &y[0] {
		z = makeN(nil, m+n, true);  // z is an alias for x or y - cannot reuse
	}
	for i := 0; i < n; i++ {
		if f := y[i]; f != 0 {
			z[m+i] = addMulVVW(&z[i], &x[0], f, m);
		}
	}
	z = normN(z);

	return z
}

// q = (x-r)/y, with 0 <= r < y
func divNW(z, x []Word, y Word) (q []Word, r Word) {
	m := len(x);
	switch {
	case y == 0:
		panic("division by zero");
	case y == 1:
		q = setN(z, x);  // result is x
		return;
	case m == 0:
		q = setN(z, nil);  // result is 0
		return;
	}
	// m > 0
	z = makeN(z, m, false);
	r = divWVW(&z[0], 0, &x[0], y, m);
	q = normN(z);
	return;
}

// log2 computes the integer binary logarithm of x.
// The result is the integer n for which 2^n <= x < 2^(n+1).
// If x == 0, the result is -1.
func log2(x Word) int {
	n := 0;
	for ; x > 0; x >>= 1 {
		n++;
	}
	return n-1;
}

// log2N computes the integer binary logarithm of x.
// The result is the integer n for which 2^n <= x < 2^(n+1).
// If x == 0, the result is -1.
func log2N(x []Word) int {
	m := len(x);
	if m > 0 {
		return (m-1)*int(_W) + log2(x[m-1]);
	}
	return -1;
}

func hexValue(ch byte) int {
	var d byte;
	switch {
	case '0' <= ch && ch <= '9': d = ch - '0';
	case 'a' <= ch && ch <= 'f': d = ch - 'a' + 10;
	case 'A' <= ch && ch <= 'F': d = ch - 'A' + 10;
	default: return -1;
	}
	return int(d);
}

// scanN returns the natural number corresponding to the
// longest possible prefix of s representing a natural number in a
// given conversion base, the actual conversion base used, and the
// prefix length. The syntax of natural numbers follows the syntax
// of unsigned integer literals in Go.
//
// If the base argument is 0, the string prefix determines the actual
// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
// ``0'' prefix selects base 8. Otherwise the selected base is 10.
//
func scanN(z []Word, s string, base int) ([]Word, int, int) {
	// determine base if necessary
	i, n := 0, len(s);
	if base == 0 {
		base = 10;
		if n > 0 && s[0] == '0' {
			if n > 1 && (s[1] == 'x' || s[1] == 'X') {
				base, i = 16, 2;
			} else {
				base, i = 8, 1;
			}
		}
	}
	if base < 2 || 16 < base {
		panic("illegal base");
	}

	// convert string
	z = makeN(z, len(z), false);
	for ; i < n; i++ {
		d := hexValue(s[i]);
		if 0 <= d && d < base {
			z = mulAddNWW(z, z, Word(base), Word(d));
		} else {
			break;
		}
	}

	return z, base, i;
}

// string converts x to a string for a given base, with 2 <= base <= 16.
// TODO(gri) in the style of the other routines, perhaps this should take
//           a []byte buffer and return it
func stringN(x []Word, base int) string {
	if base < 2 || 16 < base {
		panic("illegal base");
	}

	if len(x) == 0 {
		return "0";
	}

	// allocate buffer for conversion
	i := (log2N(x) + 1) / log2(Word(base)) + 1;  // +1: round up
	s := make([]byte, i);

	// don't destroy x
	q := setN(nil, x);

	// convert
	for len(q) > 0 {
		i--;
		var r Word;
		q, r = divNW(q, q, 10);
		s[i] = "0123456789abcdef"[r];
	};

	return string(s[i : len(s)]);
}
<commit_msg>added "Under construction" to package comment<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains operations on unsigned multi-precision integers.
// These are the building blocks for the operations on signed integers
// and rationals.

//	NOTE: PACKAGE UNDER CONSTRUCTION (use bignum for the time being)
//
// This package implements multi-precision arithmetic (big numbers).
// The following numeric types are supported:
//
//	- Int	signed integers
//
// All methods on Int take the result as the receiver; if it is one
// of the operands it may be overwritten (and its memory reused).
// To enable chaining of operations, the result is also returned.
//
package big

// An unsigned integer x of the form
//
//   x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0]
//
// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n,
// with the digits x[i] as the slice elements.
//
// A number is normalized if the slice contains no leading 0 digits.
// During arithmetic operations, denormalized values may occur but are
// always normalized before returning the final result. The normalized
// representation of 0 is the empty or nil slice (length = 0).

// TODO(gri) - convert these routines into methods for type 'nat'
//           - decide if type 'nat' should be exported

func normN(z []Word) []Word {
	i := len(z);
	for i > 0 && z[i-1] == 0 {
		i--;
	}
	z = z[0 : i];
	return z;
}

func makeN(z []Word, m int, clear bool) []Word {
	if len(z) > m {
		z = z[0 : m];  // reuse z - has at least one extra word for a carry, if any
		if clear {
			for i := range z {
				z[i] = 0;
			}
		}
		return z;
	}

	c := 4;  // minimum capacity
	if m > c {
		c = m;
	}
	return make([]Word, m, c+1);  // +1: extra word for a carry, if any
}

func newN(z []Word, x uint64) []Word {
	if x == 0 {
		return makeN(z, 0, false);
	}

	// single-digit values
	if x == uint64(Word(x)) {
		z = makeN(z, 1, false);
		z[0] = Word(x);
		return z;
	}

	// compute number of words n required to represent x
	n := 0;
	for t := x; t > 0; t >>= _W {
		n++;
	}

	// split x into n words
	z = makeN(z, n, false);
	for i := 0; i < n; i++ {
		z[i] = Word(x & _M);
		x >>= _W;
	}

	return z;
}

func setN(z, x []Word) []Word {
	z = makeN(z, len(x), false);
	for i, d := range x {
		z[i] = d;
	}
	return z;
}

func addNN(z, x, y []Word) []Word {
	m := len(x);
	n := len(y);

	switch {
	case m < n:
		return addNN(z, y, x);
	case m == 0:
		// n == 0 because m >= n; result is 0
		return makeN(z, 0, false);
	case n == 0:
		// result is x
		return setN(z, x);
	}
	// m > 0

	z = makeN(z, m, false);
	c := addVV(&z[0], &x[0], &y[0], n);
	if m > n {
		c = addVW(&z[n], &x[n], c, m-n);
	}
	if c > 0 {
		z = z[0 : m+1];
		z[m] = c;
	}

	return z;
}

func subNN(z, x, y []Word) []Word {
	m := len(x);
	n := len(y);

	switch {
	case m < n:
		panic("underflow");
	case m == 0:
		// n == 0 because m >= n; result is 0
		return makeN(z, 0, false);
	case n == 0:
		// result is x
		return setN(z, x);
	}
	// m > 0

	z = makeN(z, m, false);
	c := subVV(&z[0], &x[0], &y[0], n);
	if m > n {
		c = subVW(&z[n], &x[n], c, m-n);
	}
	if c != 0 {
		panic("underflow");
	}
	z = normN(z);

	return z;
}

func cmpNN(x, y []Word) (r int) {
	m := len(x);
	n := len(y);
	if m != n || m == 0 {
		switch {
		case m < n: r = -1;
		case m > n: r = 1;
		}
		return;
	}

	i := m-1;
	for i > 0 && x[i] == y[i] {
		i--;
	}

	switch {
	case x[i] < y[i]: r = -1;
	case x[i] > y[i]: r = 1;
	}
	return;
}

func mulAddNWW(z, x []Word, y, r Word) []Word {
	m := len(x);
	if m == 0 || y == 0 {
		return newN(z, uint64(r));	// result is r
	}
	// m > 0

	z = makeN(z, m, false);
	c := mulAddVWW(&z[0], &x[0], y, r, m);
	if c > 0 {
		z = z[0 : m+1];
		z[m] = c;
	}

	return z;
}

func mulNN(z, x, y []Word) []Word {
	m := len(x);
	n := len(y);

	switch {
	case m < n:
		return mulNN(z, y, x);
	case m == 0 || n == 0:
		return makeN(z, 0, false);
	case n == 1:
		return mulAddNWW(z, x, y[0], 0);
	}
	// m >= n && m > 1 && n > 1

	z = makeN(z, m+n, true);
	if &z[0] == &x[0] || &z[0] == &y[0] {
		z = makeN(nil, m+n, true);  // z is an alias for x or y - cannot reuse
	}
	for i := 0; i < n; i++ {
		if f := y[i]; f != 0 {
			z[m+i] = addMulVVW(&z[i], &x[0], f, m);
		}
	}
	z = normN(z);

	return z
}

// q = (x-r)/y, with 0 <= r < y
func divNW(z, x []Word, y Word) (q []Word, r Word) {
	m := len(x);
	switch {
	case y == 0:
		panic("division by zero");
	case y == 1:
		q = setN(z, x);  // result is x
		return;
	case m == 0:
		q = setN(z, nil);  // result is 0
		return;
	}
	// m > 0
	z = makeN(z, m, false);
	r = divWVW(&z[0], 0, &x[0], y, m);
	q = normN(z);
	return;
}

// log2 computes the integer binary logarithm of x.
// The result is the integer n for which 2^n <= x < 2^(n+1).
// If x == 0, the result is -1.
func log2(x Word) int {
	n := 0;
	for ; x > 0; x >>= 1 {
		n++;
	}
	return n-1;
}

// log2N computes the integer binary logarithm of x.
// The result is the integer n for which 2^n <= x < 2^(n+1).
// If x == 0, the result is -1.
func log2N(x []Word) int {
	m := len(x);
	if m > 0 {
		return (m-1)*int(_W) + log2(x[m-1]);
	}
	return -1;
}

func hexValue(ch byte) int {
	var d byte;
	switch {
	case '0' <= ch && ch <= '9': d = ch - '0';
	case 'a' <= ch && ch <= 'f': d = ch - 'a' + 10;
	case 'A' <= ch && ch <= 'F': d = ch - 'A' + 10;
	default: return -1;
	}
	return int(d);
}

// scanN returns the natural number corresponding to the
// longest possible prefix of s representing a natural number in a
// given conversion base, the actual conversion base used, and the
// prefix length. The syntax of natural numbers follows the syntax
// of unsigned integer literals in Go.
//
// If the base argument is 0, the string prefix determines the actual
// conversion base. A prefix of ``0x'' or ``0X'' selects base 16; the
// ``0'' prefix selects base 8. Otherwise the selected base is 10.
//
func scanN(z []Word, s string, base int) ([]Word, int, int) {
	// determine base if necessary
	i, n := 0, len(s);
	if base == 0 {
		base = 10;
		if n > 0 && s[0] == '0' {
			if n > 1 && (s[1] == 'x' || s[1] == 'X') {
				base, i = 16, 2;
			} else {
				base, i = 8, 1;
			}
		}
	}
	if base < 2 || 16 < base {
		panic("illegal base");
	}

	// convert string
	z = makeN(z, len(z), false);
	for ; i < n; i++ {
		d := hexValue(s[i]);
		if 0 <= d && d < base {
			z = mulAddNWW(z, z, Word(base), Word(d));
		} else {
			break;
		}
	}

	return z, base, i;
}

// string converts x to a string for a given base, with 2 <= base <= 16.
// TODO(gri) in the style of the other routines, perhaps this should take
//           a []byte buffer and return it
func stringN(x []Word, base int) string {
	if base < 2 || 16 < base {
		panic("illegal base");
	}

	if len(x) == 0 {
		return "0";
	}

	// allocate buffer for conversion
	i := (log2N(x) + 1) / log2(Word(base)) + 1;  // +1: round up
	s := make([]byte, i);

	// don't destroy x
	q := setN(nil, x);

	// convert
	for len(q) > 0 {
		i--;
		var r Word;
		q, r = divNW(q, q, 10);
		s[i] = "0123456789abcdef"[r];
	};

	return string(s[i : len(s)]);
}
<|endoftext|>


<commit_before>// Copyright 2009 The Go 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 fmt implements formatted I/O with functions analogous
	to C's printf and scanf.  The format 'verbs' are derived from C's but
	are simpler.

	Printing:

	The verbs:

	General:
		%v	the value in a default format.
			when printing structs, the plus flag (%+v) adds field names
		%#v	a Go-syntax representation of the value
		%T	a Go-syntax representation of the type of the value
		%%	a literal percent sign; consumes no value

	Boolean:
		%t	the word true or false
	Integer:
		%b	base 2
		%c	the character represented by the corresponding Unicode code point
		%d	base 10
		%o	base 8
		%x	base 16, with lower-case letters for a-f
		%X	base 16, with upper-case letters for A-F
		%U	Unicode format: U+1234; same as "U+%x" with 4 digits default
	Floating-point and complex constituents:
		%b	decimalless scientific notation with exponent a power
			of two, in the manner of strconv.Ftoa32, e.g. -123456p-78
		%e	scientific notation, e.g. -1234.456e+78
		%E	scientific notation, e.g. -1234.456E+78
		%f	decimal point but no exponent, e.g. 123.456
		%g	whichever of %e or %f produces more compact output
		%G	whichever of %E or %f produces more compact output
	String and slice of bytes:
		%s	the uninterpreted bytes of the string or slice
		%q	a double-quoted string safely escaped with Go syntax
		%x	base 16, lower-case, two characters per byte
		%X	base 16, upper-case, two characters per byte
	Pointer:
		%p	base 16 notation, with leading 0x

	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
	Similarly, there is no need to specify the size of the operand (int8, int64).

	The width and precision control formatting and are in units of Unicode
	code points.  (This differs from C's printf where the units are numbers
	of bytes.) Either or both of the flags may be replaced with the
	character '*', causing their values to be obtained from the next
	operand, which must be of type int.

	For numeric values, width sets the width of the field and precision
	sets the number of places after the decimal, if appropriate.  For
	example, the format %6.2f prints 123.45.

	For strings, width is the minimum number of characters to output,
	padding with spaces if necessary, and precision is the maximum
	number of characters to output, truncating if necessary.

	Other flags:
		+	always print a sign for numeric values
		-	pad with spaces on the right rather than the left (left-justify the field)
		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
			0X for hex (%#X); suppress 0x for %p (%#p);
			print a raw (backquoted) string if possible for %q (%#q)
		' '	(space) leave a space for elided sign in numbers (% d);
			put spaces between bytes printing strings or slices in hex (% x, % X)
		0	pad with leading zeros rather than spaces

	For each Printf-like function, there is also a Print function
	that takes no format and is equivalent to saying %v for every
	operand.  Another variant Println inserts blanks between
	operands and appends a newline.

	Regardless of the verb, if an operand is an interface value,
	the internal concrete value is used, not the interface itself.
	Thus:
		var i interface{} = 23
		fmt.Printf("%v\n", i)
	will print 23.

	If an operand implements interface Formatter, that interface
	can be used for fine control of formatting.

	If an operand implements method String() string that method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any). To avoid
	recursion in cases such as
		type X int
		func (x X) String() string { return Sprintf("%d", x) }
	cast the value before recurring:
		func (x X) String() string { return Sprintf("%d", int(x)) }

	Format errors:

	If an invalid argument is given for a verb, such as providing
	a string to %d, the generated string will contain a
	description of the problem, as in these examples:

		Wrong type or unknown verb: %!verb(type=value)
			Printf("%d", hi):          %!d(string=hi)
		Too many arguments: %!(EXTRA type=value)
			Printf("hi", "guys"):      hi%!(EXTRA string=guys)
		Too few arguments: %!verb(MISSING)
			Printf("hi%d"):            hi %!d(MISSING)
		Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
			Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
			Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi

	All errors begin with the string "%!" followed sometimes
	by a single character (the verb) and end with a parenthesized
	description.

	Scanning:

	An analogous set of functions scans formatted text to yield
	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
	Fscanf and Fscanln read from a specified os.Reader; Sscan,
	Sscanf and Sscanln read from an argument string.  Scanln,
	Fscanln and Sscanln stop scanning at a newline and require that
	the items be followed by one; Sscanf, Fscanf and Sscanf require
	newlines in the input to match newlines in the format; the other
	routines treat newlines as spaces.

	Scanf, Fscanf, and Sscanf parse the arguments according to a
	format string, analogous to that of Printf.  For example, %x
	will scan an integer as a hexadecimal number, and %v will scan
	the default representation format for the value.

	The formats behave analogously to those of Printf with the
	following exceptions:

	%p is not implemented
	%T is not implemented
	%e %E %f %F %g %g are all equivalent and scan any floating point or complex value
	%s and %v on strings scan a space-delimited token

	The familiar base-setting prefixes 0 (octal) and 0x
	(hexadecimal) are accepted when scanning integers without a
	format or with the %v verb.

	Width is interpreted in the input text (%5s means at most
	five runes of input will be read to scan a string) but there
	is no syntax for scanning with a precision (no %5.2f, just
	%5f).

	When scanning with a format, all non-empty runs of space
	characters (except newline) are equivalent to a single
	space in both the format and the input.  With that proviso,
	text in the format string must match the input text; scanning
	stops if it does not, with the return value of the function
	indicating the number of arguments scanned.

	In all the scanning functions, if an operand implements method
	Scan (that is, it implements the Scanner interface) that
	method will be used to scan the text for that operand.  Also,
	if the number of arguments scanned is less than the number of
	arguments provided, an error is returned.

	All arguments to be scanned must be either pointers to basic
	types or implementations of the Scanner interface.

	Note: Fscan etc. can read one character (rune) past the input
	they return, which means that a loop calling a scan routine
	may skip some of the input.  This is usually a problem only
	when there is no space between input values.  If the reader
	provided to Fscan implements ReadRune, that method will be used
	to read characters.  If the reader also implements UnreadRune,
	that method will be used to save the character and successive
	calls will not lose data.  To attach ReadRune and UnreadRune
	methods to a reader without that capability, use
	bufio.NewReader.
*/
package fmt
<commit_msg>fmt: tweak the doc for %U. Fixes #1727.<commit_after>// Copyright 2009 The Go 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 fmt implements formatted I/O with functions analogous
	to C's printf and scanf.  The format 'verbs' are derived from C's but
	are simpler.

	Printing:

	The verbs:

	General:
		%v	the value in a default format.
			when printing structs, the plus flag (%+v) adds field names
		%#v	a Go-syntax representation of the value
		%T	a Go-syntax representation of the type of the value
		%%	a literal percent sign; consumes no value

	Boolean:
		%t	the word true or false
	Integer:
		%b	base 2
		%c	the character represented by the corresponding Unicode code point
		%d	base 10
		%o	base 8
		%x	base 16, with lower-case letters for a-f
		%X	base 16, with upper-case letters for A-F
		%U	Unicode format: U+1234; same as "U+%0.4X"
	Floating-point and complex constituents:
		%b	decimalless scientific notation with exponent a power
			of two, in the manner of strconv.Ftoa32, e.g. -123456p-78
		%e	scientific notation, e.g. -1234.456e+78
		%E	scientific notation, e.g. -1234.456E+78
		%f	decimal point but no exponent, e.g. 123.456
		%g	whichever of %e or %f produces more compact output
		%G	whichever of %E or %f produces more compact output
	String and slice of bytes:
		%s	the uninterpreted bytes of the string or slice
		%q	a double-quoted string safely escaped with Go syntax
		%x	base 16, lower-case, two characters per byte
		%X	base 16, upper-case, two characters per byte
	Pointer:
		%p	base 16 notation, with leading 0x

	There is no 'u' flag.  Integers are printed unsigned if they have unsigned type.
	Similarly, there is no need to specify the size of the operand (int8, int64).

	The width and precision control formatting and are in units of Unicode
	code points.  (This differs from C's printf where the units are numbers
	of bytes.) Either or both of the flags may be replaced with the
	character '*', causing their values to be obtained from the next
	operand, which must be of type int.

	For numeric values, width sets the width of the field and precision
	sets the number of places after the decimal, if appropriate.  For
	example, the format %6.2f prints 123.45.

	For strings, width is the minimum number of characters to output,
	padding with spaces if necessary, and precision is the maximum
	number of characters to output, truncating if necessary.

	Other flags:
		+	always print a sign for numeric values
		-	pad with spaces on the right rather than the left (left-justify the field)
		#	alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
			0X for hex (%#X); suppress 0x for %p (%#p);
			print a raw (backquoted) string if possible for %q (%#q)
		' '	(space) leave a space for elided sign in numbers (% d);
			put spaces between bytes printing strings or slices in hex (% x, % X)
		0	pad with leading zeros rather than spaces

	For each Printf-like function, there is also a Print function
	that takes no format and is equivalent to saying %v for every
	operand.  Another variant Println inserts blanks between
	operands and appends a newline.

	Regardless of the verb, if an operand is an interface value,
	the internal concrete value is used, not the interface itself.
	Thus:
		var i interface{} = 23
		fmt.Printf("%v\n", i)
	will print 23.

	If an operand implements interface Formatter, that interface
	can be used for fine control of formatting.

	If an operand implements method String() string that method
	will be used to convert the object to a string, which will then
	be formatted as required by the verb (if any). To avoid
	recursion in cases such as
		type X int
		func (x X) String() string { return Sprintf("%d", x) }
	cast the value before recurring:
		func (x X) String() string { return Sprintf("%d", int(x)) }

	Format errors:

	If an invalid argument is given for a verb, such as providing
	a string to %d, the generated string will contain a
	description of the problem, as in these examples:

		Wrong type or unknown verb: %!verb(type=value)
			Printf("%d", hi):          %!d(string=hi)
		Too many arguments: %!(EXTRA type=value)
			Printf("hi", "guys"):      hi%!(EXTRA string=guys)
		Too few arguments: %!verb(MISSING)
			Printf("hi%d"):            hi %!d(MISSING)
		Non-int for width or precision: %!(BADWIDTH) or %!(BADPREC)
			Printf("%*s", 4.5, "hi"):  %!(BADWIDTH)hi
			Printf("%.*s", 4.5, "hi"): %!(BADPREC)hi

	All errors begin with the string "%!" followed sometimes
	by a single character (the verb) and end with a parenthesized
	description.

	Scanning:

	An analogous set of functions scans formatted text to yield
	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
	Fscanf and Fscanln read from a specified os.Reader; Sscan,
	Sscanf and Sscanln read from an argument string.  Scanln,
	Fscanln and Sscanln stop scanning at a newline and require that
	the items be followed by one; Sscanf, Fscanf and Sscanf require
	newlines in the input to match newlines in the format; the other
	routines treat newlines as spaces.

	Scanf, Fscanf, and Sscanf parse the arguments according to a
	format string, analogous to that of Printf.  For example, %x
	will scan an integer as a hexadecimal number, and %v will scan
	the default representation format for the value.

	The formats behave analogously to those of Printf with the
	following exceptions:

	%p is not implemented
	%T is not implemented
	%e %E %f %F %g %g are all equivalent and scan any floating point or complex value
	%s and %v on strings scan a space-delimited token

	The familiar base-setting prefixes 0 (octal) and 0x
	(hexadecimal) are accepted when scanning integers without a
	format or with the %v verb.

	Width is interpreted in the input text (%5s means at most
	five runes of input will be read to scan a string) but there
	is no syntax for scanning with a precision (no %5.2f, just
	%5f).

	When scanning with a format, all non-empty runs of space
	characters (except newline) are equivalent to a single
	space in both the format and the input.  With that proviso,
	text in the format string must match the input text; scanning
	stops if it does not, with the return value of the function
	indicating the number of arguments scanned.

	In all the scanning functions, if an operand implements method
	Scan (that is, it implements the Scanner interface) that
	method will be used to scan the text for that operand.  Also,
	if the number of arguments scanned is less than the number of
	arguments provided, an error is returned.

	All arguments to be scanned must be either pointers to basic
	types or implementations of the Scanner interface.

	Note: Fscan etc. can read one character (rune) past the input
	they return, which means that a loop calling a scan routine
	may skip some of the input.  This is usually a problem only
	when there is no space between input values.  If the reader
	provided to Fscan implements ReadRune, that method will be used
	to read characters.  If the reader also implements UnreadRune,
	that method will be used to save the character and successive
	calls will not lose data.  To attach ReadRune and UnreadRune
	methods to a reader without that capability, use
	bufio.NewReader.
*/
package fmt
<|endoftext|>


<commit_before>// Copyright 2009 The Go 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 net provides a portable interface for network I/O, including
TCP/IP, UDP, domain name resolution, and Unix domain sockets.

Although the package provides access to low-level networking
primitives, most clients will need only the basic interface
provided by the Dial, Listen, and Accept functions.

The Dial function connects to a server:

	conn, err := net.Dial("tcp", "google.com:80")
	if err != nil {
		// handle error
	}
	fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
	status, err := bufio.NewReader(conn).ReadString('\n')
	// ...

The Listen function creates servers:

	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		// handle error
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// handle error
			continue
		}
		go handleConnection(conn)
	}
*/
package net

// TODO(rsc):
//	support for raw ethernet sockets

import (
	"errors"
	"time"
)

// Addr represents a network end point address.
type Addr interface {
	Network() string // name of the network
	String() string  // string form of address
}

// Conn is a generic stream-oriented network connection.
type Conn interface {
	// Read reads data from the connection.
	// Read can be made to time out and return a Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetReadDeadline.
	Read(b []byte) (n int, err error)

	// Write writes data to the connection.
	// Write can be made to time out and return a Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetWriteDeadline.
	Write(b []byte) (n int, err error)

	// Close closes the connection.
	Close() error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// RemoteAddr returns the remote network address.
	RemoteAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for all Read calls to return.
	// If the deadline is reached, Read will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Read will not time out.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for all Write calls to return.
	// If the deadline is reached, Write will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Write will not time out.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	SetWriteDeadline(t time.Time) error
}

// An Error represents a network error.
type Error interface {
	error
	Timeout() bool   // Is the error a timeout?
	Temporary() bool // Is the error temporary?
}

// PacketConn is a generic packet-oriented network connection.
type PacketConn interface {
	// ReadFrom reads a packet from the connection,
	// copying the payload into b.  It returns the number of
	// bytes copied into b and the return address that
	// was on the packet.
	// ReadFrom can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetDeadline and SetReadDeadline.
	ReadFrom(b []byte) (n int, addr Addr, err error)

	// WriteTo writes a packet with payload b to addr.
	// WriteTo can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetDeadline and SetWriteDeadline.
	// On packet-oriented connections, write timeouts are rare.
	WriteTo(b []byte, addr Addr) (n int, err error)

	// Close closes the connection.
	Close() error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for all Read calls to return.
	// If the deadline is reached, Read will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Read will not time out.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for all Write calls to return.
	// If the deadline is reached, Write will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Write will not time out.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	SetWriteDeadline(t time.Time) error
}

// A Listener is a generic network listener for stream-oriented protocols.
type Listener interface {
	// Accept waits for and returns the next connection to the listener.
	Accept() (c Conn, err error)

	// Close closes the listener.
	Close() error

	// Addr returns the listener's network address.
	Addr() Addr
}

var errMissingAddress = errors.New("missing address")

type OpError struct {
	Op   string
	Net  string
	Addr Addr
	Err  error
}

func (e *OpError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Op
	if e.Net != "" {
		s += " " + e.Net
	}
	if e.Addr != nil {
		s += " " + e.Addr.String()
	}
	s += ": " + e.Err.Error()
	return s
}

type temporary interface {
	Temporary() bool
}

func (e *OpError) Temporary() bool {
	t, ok := e.Err.(temporary)
	return ok && t.Temporary()
}

type timeout interface {
	Timeout() bool
}

func (e *OpError) Timeout() bool {
	t, ok := e.Err.(timeout)
	return ok && t.Timeout()
}

type timeoutError struct{}

func (e *timeoutError) Error() string   { return "i/o timeout" }
func (e *timeoutError) Timeout() bool   { return true }
func (e *timeoutError) Temporary() bool { return true }

var errTimeout error = &timeoutError{}

type AddrError struct {
	Err  string
	Addr string
}

func (e *AddrError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Err
	if e.Addr != "" {
		s += " " + e.Addr
	}
	return s
}

func (e *AddrError) Temporary() bool {
	return false
}

func (e *AddrError) Timeout() bool {
	return false
}

type UnknownNetworkError string

func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
func (e UnknownNetworkError) Temporary() bool { return false }
func (e UnknownNetworkError) Timeout() bool   { return false }

// DNSConfigError represents an error reading the machine's DNS configuration.
type DNSConfigError struct {
	Err error
}

func (e *DNSConfigError) Error() string {
	return "error reading DNS config: " + e.Err.Error()
}

func (e *DNSConfigError) Timeout() bool   { return false }
func (e *DNSConfigError) Temporary() bool { return false }
<commit_msg>net: more docs on deadlines<commit_after>// Copyright 2009 The Go 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 net provides a portable interface for network I/O, including
TCP/IP, UDP, domain name resolution, and Unix domain sockets.

Although the package provides access to low-level networking
primitives, most clients will need only the basic interface provided
by the Dial, Listen, and Accept functions and the associated
Conn and Listener interfaces. The crypto/tls package uses
the same interfaces and similar Dial and Listen functions.

The Dial function connects to a server:

	conn, err := net.Dial("tcp", "google.com:80")
	if err != nil {
		// handle error
	}
	fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
	status, err := bufio.NewReader(conn).ReadString('\n')
	// ...

The Listen function creates servers:

	ln, err := net.Listen("tcp", ":8080")
	if err != nil {
		// handle error
	}
	for {
		conn, err := ln.Accept()
		if err != nil {
			// handle error
			continue
		}
		go handleConnection(conn)
	}
*/
package net

// TODO(rsc):
//	support for raw ethernet sockets

import (
	"errors"
	"time"
)

// Addr represents a network end point address.
type Addr interface {
	Network() string // name of the network
	String() string  // string form of address
}

// Conn is a generic stream-oriented network connection.
type Conn interface {
	// Read reads data from the connection.
	// Read can be made to time out and return a Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetReadDeadline.
	Read(b []byte) (n int, err error)

	// Write writes data to the connection.
	// Write can be made to time out and return a Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetWriteDeadline.
	Write(b []byte) (n int, err error)

	// Close closes the connection.
	Close() error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// RemoteAddr returns the remote network address.
	RemoteAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection. It is equivalent to calling both
	// SetReadDeadline and SetWriteDeadline.
	//
	// A deadline is an absolute time after which I/O operations
	// fail with a timeout (see type Error) instead of
	// blocking. The deadline applies to all future I/O, not just
	// the immediately following call to Read or Write.
	//
	// An idle timeout can be implemented by repeatedly extending
	// the deadline after successful Read or Write calls.
	//
	// A zero value for t means I/O operations will not time out.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for Read calls.
	// A zero value for t means Read will not time out.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for Write calls.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	// A zero value for t means Write will not time out.
	SetWriteDeadline(t time.Time) error
}

// An Error represents a network error.
type Error interface {
	error
	Timeout() bool   // Is the error a timeout?
	Temporary() bool // Is the error temporary?
}

// PacketConn is a generic packet-oriented network connection.
type PacketConn interface {
	// ReadFrom reads a packet from the connection,
	// copying the payload into b.  It returns the number of
	// bytes copied into b and the return address that
	// was on the packet.
	// ReadFrom can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetDeadline and SetReadDeadline.
	ReadFrom(b []byte) (n int, addr Addr, err error)

	// WriteTo writes a packet with payload b to addr.
	// WriteTo can be made to time out and return
	// an error with Timeout() == true after a fixed time limit;
	// see SetDeadline and SetWriteDeadline.
	// On packet-oriented connections, write timeouts are rare.
	WriteTo(b []byte, addr Addr) (n int, err error)

	// Close closes the connection.
	Close() error

	// LocalAddr returns the local network address.
	LocalAddr() Addr

	// SetDeadline sets the read and write deadlines associated
	// with the connection.
	SetDeadline(t time.Time) error

	// SetReadDeadline sets the deadline for all Read calls to return.
	// If the deadline is reached, Read will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Read will not time out.
	SetReadDeadline(t time.Time) error

	// SetWriteDeadline sets the deadline for all Write calls to return.
	// If the deadline is reached, Write will fail with a timeout
	// (see type Error) instead of blocking.
	// A zero value for t means Write will not time out.
	// Even if write times out, it may return n > 0, indicating that
	// some of the data was successfully written.
	SetWriteDeadline(t time.Time) error
}

// A Listener is a generic network listener for stream-oriented protocols.
type Listener interface {
	// Accept waits for and returns the next connection to the listener.
	Accept() (c Conn, err error)

	// Close closes the listener.
	Close() error

	// Addr returns the listener's network address.
	Addr() Addr
}

var errMissingAddress = errors.New("missing address")

type OpError struct {
	Op   string
	Net  string
	Addr Addr
	Err  error
}

func (e *OpError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Op
	if e.Net != "" {
		s += " " + e.Net
	}
	if e.Addr != nil {
		s += " " + e.Addr.String()
	}
	s += ": " + e.Err.Error()
	return s
}

type temporary interface {
	Temporary() bool
}

func (e *OpError) Temporary() bool {
	t, ok := e.Err.(temporary)
	return ok && t.Temporary()
}

type timeout interface {
	Timeout() bool
}

func (e *OpError) Timeout() bool {
	t, ok := e.Err.(timeout)
	return ok && t.Timeout()
}

type timeoutError struct{}

func (e *timeoutError) Error() string   { return "i/o timeout" }
func (e *timeoutError) Timeout() bool   { return true }
func (e *timeoutError) Temporary() bool { return true }

var errTimeout error = &timeoutError{}

type AddrError struct {
	Err  string
	Addr string
}

func (e *AddrError) Error() string {
	if e == nil {
		return "<nil>"
	}
	s := e.Err
	if e.Addr != "" {
		s += " " + e.Addr
	}
	return s
}

func (e *AddrError) Temporary() bool {
	return false
}

func (e *AddrError) Timeout() bool {
	return false
}

type UnknownNetworkError string

func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
func (e UnknownNetworkError) Temporary() bool { return false }
func (e UnknownNetworkError) Timeout() bool   { return false }

// DNSConfigError represents an error reading the machine's DNS configuration.
type DNSConfigError struct {
	Err error
}

func (e *DNSConfigError) Error() string {
	return "error reading DNS config: " + e.Err.Error()
}

func (e *DNSConfigError) Timeout() bool   { return false }
func (e *DNSConfigError) Temporary() bool { return false }
<|endoftext|>


<commit_before>package session

import (
	"io"
	"net"
)

var m map[int]Service

// Session represents an active pairing of two Transfer instances, and allows
// clients (in one instance) to open a connection to services in the other.
type Session interface {
	OpenConnection(id int) Connection
}

// Connection wraps a TCP connection between a client and service.
type Connection interface {
	io.ReadWriteCloser
}

// Service is the interface that should be implemented by all services in the
// app.
//
// Every service should create an implementation of Service, and register it
// using RegisterService.
type Service interface {
	HandleConnection(session Session, connection Connection)
}

// GetSession returns the current session, or an error if one is not available.
// For initial testing purposes, GetSession just returns a loopback service.
func GetSession() (Session, error) {
	return &loopbackService{}, nil
}

//
// Every service should create an implementation of Service, and register it
// using RegisterService.
func RegisterService(id int, service Service) {
	if id < 0 || id > 255 {
		panic("Invalid ID")
	}
	m[id] = service
}

// Loopback service for initial testing.
// TODO: Delete this.
type loopbackService struct{}

func (l *loopbackService) OpenConnection(id int) Connection {
	if id < 0 || id > 255 {
		panic("Invalid ID")
	}
	s, ok := m[id]
	if !ok {
		panic("Service ID not found")
	}
	conn1, conn2 := net.Pipe()
	s.HandleConnection(l, conn1)
	return conn2
}

// For initial go environment testing.
// TODO: Delete this.
func GetTestString() string {
	return "It wroks!"
}
<commit_msg>Bugfix: loopbackService.OpenConnection didn't start server handler in new thread.<commit_after>package session

import (
	"io"
	"net"
)

var m map[int]Service

// Session represents an active pairing of two Transfer instances, and allows
// clients (in one instance) to open a connection to services in the other.
type Session interface {
	OpenConnection(id int) Connection
}

// Connection wraps a TCP connection between a client and service.
type Connection interface {
	io.ReadWriteCloser
}

// Service is the interface that should be implemented by all services in the
// app.
//
// Every service should create an implementation of Service, and register it
// using RegisterService.
type Service interface {
	HandleConnection(session Session, connection Connection)
}

// GetSession returns the current session, or an error if one is not available.
// For initial testing purposes, GetSession just returns a loopback service.
func GetSession() (Session, error) {
	return &loopbackService{}, nil
}

//
// Every service should create an implementation of Service, and register it
// using RegisterService.
func RegisterService(id int, service Service) {
	if id < 0 || id > 255 {
		panic("Invalid ID")
	}
	m[id] = service
}

// Loopback service for initial testing.
// TODO: Delete this.
type loopbackService struct{}

func (l *loopbackService) OpenConnection(id int) Connection {
	if id < 0 || id > 255 {
		panic("Invalid ID")
	}
	s, ok := m[id]
	if !ok {
		panic("Service ID not found")
	}
	conn1, conn2 := net.Pipe()
	go s.HandleConnection(l, conn1)
	return conn2
}

// For initial go environment testing.
// TODO: Delete this.
func GetTestString() string {
	return "It wroks!"
}
<|endoftext|>


<commit_before>// Methods dealing with files writing/reading
// from either the FS or a distant service (s3, ...)
// Copyright © 2015 - Rémy MATHIEU
package server

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/s3"
)

func (s *Server) createS3Config(creds *credentials.Credentials, region string) *aws.Config {
	return &aws.Config{
		Credentials: creds,
		Region:      region,
	}
}

// writeFile deals with writing the file, using the flags
// to know where and the filename / data to store it.
func (s *Server) WriteFile(filename string, data []byte) error {
	if s.Config.Storage == FS_STORAGE {
		file, err := os.Create(s.Config.FSConfig.OutputDirectory + "/" + filename)
		if err != nil {
			log.Println("[err] Can't create the file to write: ", filename)
			return err
		}

		_, err = file.Write(data)
		if err != nil {
			log.Println("[err] Can't write the file to write: ", filename)
			return err
		}

		err = file.Close()
		if err != nil {
			log.Println("[err] Can't close the file to write: ", filename)
			return err
		}
		return nil
	} else if s.Config.Storage == S3_STORAGE {
		// S3 connection
		creds := credentials.NewStaticCredentials(s.Config.S3Config.AccessKey, s.Config.S3Config.AccessSecret, "")
		client := s3.New(s.createS3Config(creds, s.Config.S3Config.Region))
		body := bytes.NewReader(data)

		// Creates the S3 put request
		por := &s3.PutObjectInput{
			Body:          body,
			Key:           aws.String(filename),
			ContentLength: aws.Long(int64(len(data))),
			Bucket:        aws.String(s.Config.S3Config.Bucket),
		}

		// Sends the S3 put request
		_, err := client.PutObject(por)
		if err != nil {
			return err
		}
	}

	return fmt.Errorf("[err] Unsupported storage: %s", s.Config.Storage)
}

// readFile is the method to read the file from wherever it
// is stored. The serverFlags are used to know where to read,
// the filename is used to know what to read.
func (s *Server) ReadFile(filename string) ([]byte, error) {
	if s.Config.Storage == FS_STORAGE {
		file, err := os.Open(s.Config.FSConfig.OutputDirectory + "/" + filename)
		if err != nil {
			return nil, err
		}

		data, err := ioutil.ReadAll(file)
		if err != nil {
			return nil, err
		}

		return data, nil
	} else if s.Config.Storage == S3_STORAGE {
		// S3 connection
		creds := credentials.NewStaticCredentials(s.Config.S3Config.AccessKey, s.Config.S3Config.AccessSecret, "")
		client := s3.New(s.createS3Config(creds, s.Config.S3Config.Region))

		// The get request
		gor := &s3.GetObjectInput{
			Key:    aws.String(filename),
			Bucket: aws.String(s.Config.S3Config.Bucket),
		}

		// Sends the request
		resp, err := client.GetObject(gor)
		if err != nil {
			return nil, err
		}

		// Reads the result
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Println("[err] Can't read the body of a GetObjectOutput from AWS")
			log.Println(err)
			return nil, err
		}

		return data, nil
	}

	return nil, fmt.Errorf("[err] Unsupported storage: %s", s.Config.Storage)
}

// Expire expires a file : delete it from the metadata
// and from the FS.
func (s *Server) Expire(m Metadata) error {
	filename := m.Filename

	// delete from the datbase
	s.deleteMetadata(filename)

	if s.Config.Storage == FS_STORAGE {
		return os.Remove(s.Config.RuntimeDir + "/" + filename)
	} else if s.Config.Storage == S3_STORAGE {
		// S3 connection
		creds := credentials.NewStaticCredentials(s.Config.S3Config.AccessKey, s.Config.S3Config.AccessSecret, "")
		client := s3.New(s.createS3Config(creds, s.Config.S3Config.Region))

		// The get request
		dor := &s3.DeleteObjectInput{
			Key:    aws.String(filename),
			Bucket: aws.String(s.Config.S3Config.Bucket),
		}

		_, err := client.DeleteObject(dor)
		if err != nil {
			return err
		}

		return nil
	}

	return fmt.Errorf("[err] Unsupported storage: %s", s.Config.Storage)
}

// computeEndOfLife return as a string the end of life of the new file.
func (s *Server) computeEndOfLife(ttl string, now time.Time) time.Time {
	if len(ttl) == 0 {
		return time.Time{}
	}
	duration, _ := time.ParseDuration(ttl) // no error possible 'cause already checked in the controller
	t := now.Add(duration)
	return t
}
<commit_msg>Fix the Expire method: remove the file from the output directory<commit_after>// Methods dealing with files writing/reading
// from either the FS or a distant service (s3, ...)
// Copyright © 2015 - Rémy MATHIEU
package server

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"time"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/service/s3"
)

func (s *Server) createS3Config(creds *credentials.Credentials, region string) *aws.Config {
	return &aws.Config{
		Credentials: creds,
		Region:      region,
	}
}

// writeFile deals with writing the file, using the flags
// to know where and the filename / data to store it.
func (s *Server) WriteFile(filename string, data []byte) error {
	if s.Config.Storage == FS_STORAGE {
		file, err := os.Create(s.Config.FSConfig.OutputDirectory + "/" + filename)
		if err != nil {
			log.Println("[err] Can't create the file to write: ", filename)
			return err
		}

		_, err = file.Write(data)
		if err != nil {
			log.Println("[err] Can't write the file to write: ", filename)
			return err
		}

		err = file.Close()
		if err != nil {
			log.Println("[err] Can't close the file to write: ", filename)
			return err
		}
		return nil
	} else if s.Config.Storage == S3_STORAGE {
		// S3 connection
		creds := credentials.NewStaticCredentials(s.Config.S3Config.AccessKey, s.Config.S3Config.AccessSecret, "")
		client := s3.New(s.createS3Config(creds, s.Config.S3Config.Region))
		body := bytes.NewReader(data)

		// Creates the S3 put request
		por := &s3.PutObjectInput{
			Body:          body,
			Key:           aws.String(filename),
			ContentLength: aws.Long(int64(len(data))),
			Bucket:        aws.String(s.Config.S3Config.Bucket),
		}

		// Sends the S3 put request
		_, err := client.PutObject(por)
		if err != nil {
			return err
		}
	}

	return fmt.Errorf("[err] Unsupported storage: %s", s.Config.Storage)
}

// readFile is the method to read the file from wherever it
// is stored. The serverFlags are used to know where to read,
// the filename is used to know what to read.
func (s *Server) ReadFile(filename string) ([]byte, error) {
	if s.Config.Storage == FS_STORAGE {
		file, err := os.Open(s.Config.FSConfig.OutputDirectory + "/" + filename)
		if err != nil {
			return nil, err
		}

		data, err := ioutil.ReadAll(file)
		if err != nil {
			return nil, err
		}

		return data, nil
	} else if s.Config.Storage == S3_STORAGE {
		// S3 connection
		creds := credentials.NewStaticCredentials(s.Config.S3Config.AccessKey, s.Config.S3Config.AccessSecret, "")
		client := s3.New(s.createS3Config(creds, s.Config.S3Config.Region))

		// The get request
		gor := &s3.GetObjectInput{
			Key:    aws.String(filename),
			Bucket: aws.String(s.Config.S3Config.Bucket),
		}

		// Sends the request
		resp, err := client.GetObject(gor)
		if err != nil {
			return nil, err
		}

		// Reads the result
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Println("[err] Can't read the body of a GetObjectOutput from AWS")
			log.Println(err)
			return nil, err
		}

		return data, nil
	}

	return nil, fmt.Errorf("[err] Unsupported storage: %s", s.Config.Storage)
}

// Expire expires a file : delete it from the metadata
// and from the FS.
func (s *Server) Expire(m Metadata) error {
	filename := m.Filename

	// delete from the datbase
	s.deleteMetadata(filename)

	if s.Config.Storage == FS_STORAGE {
		return os.Remove(filepath.Join(s.Config.FSConfig.OutputDirectory, filename))
	} else if s.Config.Storage == S3_STORAGE {
		// S3 connection
		creds := credentials.NewStaticCredentials(s.Config.S3Config.AccessKey, s.Config.S3Config.AccessSecret, "")
		client := s3.New(s.createS3Config(creds, s.Config.S3Config.Region))

		// The get request
		dor := &s3.DeleteObjectInput{
			Key:    aws.String(filename),
			Bucket: aws.String(s.Config.S3Config.Bucket),
		}

		_, err := client.DeleteObject(dor)
		if err != nil {
			return err
		}

		return nil
	}

	return fmt.Errorf("[err] Unsupported storage: %s", s.Config.Storage)
}

// computeEndOfLife return as a string the end of life of the new file.
func (s *Server) computeEndOfLife(ttl string, now time.Time) time.Time {
	if len(ttl) == 0 {
		return time.Time{}
	}
	duration, _ := time.ParseDuration(ttl) // no error possible 'cause already checked in the controller
	t := now.Add(duration)
	return t
}
<|endoftext|>


<commit_before>// Methods dealing with files writing/reading
// from either the FS or a distant service (s3, ...)
// Copyright © 2015 - Rémy MATHIEU
package server

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/gen/s3"
)

// writeFile deals with writing the file, using the flags
// to know where and the filename / data to store it.
func (s *Server) WriteFile(filename string, data []byte) error {
	if s.Config.Storage == FS_STORAGE {
		file, err := os.Create(s.Config.FSConfig.OutputDirectory + "/" + filename)
		if err != nil {
			log.Println("[err] Can't create the file to write: ", filename)
			return err
		}

		_, err = file.Write(data)
		if err != nil {
			log.Println("[err] Can't write the file to write: ", filename)
			return err
		}

		err = file.Close()
		if err != nil {
			log.Println("[err] Can't close the file to write: ", filename)
			return err
		}
		return nil
	} else if s.Config.Storage == S3_STORAGE {
		// S3 connection
		creds := aws.Creds(s.Config.S3Config.AccessKey, s.Config.S3Config.AccessSecret, "")
		client := s3.New(creds, s.Config.S3Config.Region, nil)
		body := ioutil.NopCloser(bytes.NewBuffer(data))

		// Creates the S3 put request
		por := &s3.PutObjectRequest{
			Body:          body,
			Key:           aws.String(filename),
			ContentLength: aws.Long(int64(len(data))),
			Bucket:        aws.String(s.Config.S3Config.Bucket),
		}

		// Sends the S3 put request
		_, err := client.PutObject(por)
		if err != nil {
			return err
		}
	}

	return fmt.Errorf("[err] Unsupported storage: %s", s.Config.Storage)
}

// readFile is the method to read the file from wherever it
// is stored. The serverFlags are used to know where to read,
// the filename is used to know what to read.
func (s *Server) ReadFile(filename string) ([]byte, error) {
	if s.Config.Storage == FS_STORAGE {
		file, err := os.Open(s.Config.FSConfig.OutputDirectory + "/" + filename)
		if err != nil {
			return nil, err
		}

		data, err := ioutil.ReadAll(file)
		if err != nil {
			return nil, err
		}

		return data, nil
	} else if s.Config.Storage == S3_STORAGE {
		// S3 connection
		creds := aws.Creds(s.Config.S3Config.AccessKey, s.Config.S3Config.AccessSecret, "")
		client := s3.New(creds, s.Config.S3Config.Region, nil)

		// The get request
		gor := &s3.GetObjectRequest{
			Key:    aws.String(filename),
			Bucket: aws.String(s.Config.S3Config.Bucket),
		}

		// Sends the request
		resp, err := client.GetObject(gor)
		if err != nil {
			return nil, err
		}

		// Reads the result
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Println("[err] Can't read the body of a GetObjectOutput from AWS")
			log.Println(err)
			return nil, err
		}

		return data, nil
	}

	return nil, fmt.Errorf("[err] Unsupported storage: %s", s.Config.Storage)
}

// Expire expires a file : delete it from the metadata
// and from the FS.
func (s *Server) Expire(m Metadata) error {
	filename := m.Filename
	delete(s.Metadata.Data, filename)
	if s.Config.Storage == FS_STORAGE {
		return os.Remove(s.Config.RuntimeDir + "/" + filename)
	} else if s.Config.Storage == S3_STORAGE {
		// S3 connection
		creds := aws.Creds(s.Config.S3Config.AccessKey, s.Config.S3Config.AccessSecret, "")
		client := s3.New(creds, s.Config.S3Config.Region, nil)

		// The get request
		dor := &s3.DeleteObjectRequest{
			Key:    aws.String(filename),
			Bucket: aws.String(s.Config.S3Config.Bucket),
		}

		_, err := client.DeleteObject(dor)
		if err != nil {
			return err
		}

		return nil
	}

	return fmt.Errorf("[err] Unsupported storage: %s", s.Config.Storage)
}

// computeEndOfLife return as a string the end of life of the new file.
func (s *Server) computeEndOfLife(ttl string, now time.Time) time.Time {
	if len(ttl) == 0 {
		return time.Time{}
	}
	duration, _ := time.ParseDuration(ttl) // no error possible 'cause already checked in the controller
	t := now.Add(duration)
	return t
}
<commit_msg>Implement LastUploaded element removal<commit_after>// Methods dealing with files writing/reading
// from either the FS or a distant service (s3, ...)
// Copyright © 2015 - Rémy MATHIEU
package server

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/gen/s3"
)

// writeFile deals with writing the file, using the flags
// to know where and the filename / data to store it.
func (s *Server) WriteFile(filename string, data []byte) error {
	if s.Config.Storage == FS_STORAGE {
		file, err := os.Create(s.Config.FSConfig.OutputDirectory + "/" + filename)
		if err != nil {
			log.Println("[err] Can't create the file to write: ", filename)
			return err
		}

		_, err = file.Write(data)
		if err != nil {
			log.Println("[err] Can't write the file to write: ", filename)
			return err
		}

		err = file.Close()
		if err != nil {
			log.Println("[err] Can't close the file to write: ", filename)
			return err
		}
		return nil
	} else if s.Config.Storage == S3_STORAGE {
		// S3 connection
		creds := aws.Creds(s.Config.S3Config.AccessKey, s.Config.S3Config.AccessSecret, "")
		client := s3.New(creds, s.Config.S3Config.Region, nil)
		body := ioutil.NopCloser(bytes.NewBuffer(data))

		// Creates the S3 put request
		por := &s3.PutObjectRequest{
			Body:          body,
			Key:           aws.String(filename),
			ContentLength: aws.Long(int64(len(data))),
			Bucket:        aws.String(s.Config.S3Config.Bucket),
		}

		// Sends the S3 put request
		_, err := client.PutObject(por)
		if err != nil {
			return err
		}
	}

	return fmt.Errorf("[err] Unsupported storage: %s", s.Config.Storage)
}

// readFile is the method to read the file from wherever it
// is stored. The serverFlags are used to know where to read,
// the filename is used to know what to read.
func (s *Server) ReadFile(filename string) ([]byte, error) {
	if s.Config.Storage == FS_STORAGE {
		file, err := os.Open(s.Config.FSConfig.OutputDirectory + "/" + filename)
		if err != nil {
			return nil, err
		}

		data, err := ioutil.ReadAll(file)
		if err != nil {
			return nil, err
		}

		return data, nil
	} else if s.Config.Storage == S3_STORAGE {
		// S3 connection
		creds := aws.Creds(s.Config.S3Config.AccessKey, s.Config.S3Config.AccessSecret, "")
		client := s3.New(creds, s.Config.S3Config.Region, nil)

		// The get request
		gor := &s3.GetObjectRequest{
			Key:    aws.String(filename),
			Bucket: aws.String(s.Config.S3Config.Bucket),
		}

		// Sends the request
		resp, err := client.GetObject(gor)
		if err != nil {
			return nil, err
		}

		// Reads the result
		data, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Println("[err] Can't read the body of a GetObjectOutput from AWS")
			log.Println(err)
			return nil, err
		}

		return data, nil
	}

	return nil, fmt.Errorf("[err] Unsupported storage: %s", s.Config.Storage)
}

// Expire expires a file : delete it from the metadata
// and from the FS.
func (s *Server) Expire(m Metadata) error {
	filename := m.Filename
	delete(s.Metadata.Data, filename)

	lastUploaded := s.Metadata.LastUploaded
	for i, id := range lastUploaded {
		if id == filename {
			if len(lastUploaded) > 1 {
				s.Metadata.LastUploaded = append(lastUploaded[:i], lastUploaded[i+1:]...)
			} else {
				s.Metadata.LastUploaded = nil
			}
		}
	}

	if s.Config.Storage == FS_STORAGE {
		return os.Remove(s.Config.RuntimeDir + "/" + filename)
	} else if s.Config.Storage == S3_STORAGE {
		// S3 connection
		creds := aws.Creds(s.Config.S3Config.AccessKey, s.Config.S3Config.AccessSecret, "")
		client := s3.New(creds, s.Config.S3Config.Region, nil)

		// The get request
		dor := &s3.DeleteObjectRequest{
			Key:    aws.String(filename),
			Bucket: aws.String(s.Config.S3Config.Bucket),
		}

		_, err := client.DeleteObject(dor)
		if err != nil {
			return err
		}

		return nil
	}

	return fmt.Errorf("[err] Unsupported storage: %s", s.Config.Storage)
}

// computeEndOfLife return as a string the end of life of the new file.
func (s *Server) computeEndOfLife(ttl string, now time.Time) time.Time {
	if len(ttl) == 0 {
		return time.Time{}
	}
	duration, _ := time.ParseDuration(ttl) // no error possible 'cause already checked in the controller
	t := now.Add(duration)
	return t
}
<|endoftext|>


<commit_before>package rabbithole

import (
	"encoding/json"
	"net/http"
	"net/url"
)

// RuntimeParameter represents a vhost-scoped parameter.
// Value is interface{} to support creating parameters directly from types such as
// FederationUpstream and ShovelInfo.
type RuntimeParameter struct {
	Name      string      `json:"name"`
	Vhost     string      `json:"vhost"`
	Component string      `json:"component"`
	Value     interface{} `json:"value"`
}

// RuntimeParameterValue represents arbitrary parameter data.
type RuntimeParameterValue map[string]interface{}

//
// GET /api/parameters
//

// ListRuntimeParameters returns a list of all runtime parameters.
func (c *Client) ListRuntimeParameters() (params []RuntimeParameter, err error) {
	req, err := newGETRequest(c, "parameters")
	if err != nil {
		return []RuntimeParameter{}, err
	}

	if err = executeAndParseRequest(c, req, &params); err != nil {
		return []RuntimeParameter{}, err
	}

	return params, nil
}

//
// GET /api/parameters/{component}
//

// ListRuntimeParametersFor returns a list of all runtime parameters for a component in all vhosts.
func (c *Client) ListRuntimeParametersFor(component string) (params []RuntimeParameter, err error) {
	req, err := newGETRequest(c, "parameters/"+url.PathEscape(component))
	if err != nil {
		return []RuntimeParameter{}, err
	}

	if err = executeAndParseRequest(c, req, &params); err != nil {
		return []RuntimeParameter{}, err
	}

	return params, nil
}

//
// GET /api/parameters/{component}/{vhost}
//

// ListRuntimeParametersIn returns a list of all runtime parameters for a component in a vhost.
func (c *Client) ListRuntimeParametersIn(component, vhost string) (p []RuntimeParameter, err error) {
	req, err := newGETRequest(c, "parameters/"+url.PathEscape(component)+"/"+url.PathEscape(vhost))
	if err != nil {
		return []RuntimeParameter{}, err
	}

	if err = executeAndParseRequest(c, req, &p); err != nil {
		return []RuntimeParameter{}, err
	}

	return p, nil
}

//
// GET /api/parameters/{component}/{vhost}/{name}
//

// GetRuntimeParameter returns information about a runtime parameter.
func (c *Client) GetRuntimeParameter(component, vhost, name string) (p *RuntimeParameter, err error) {
	req, err := newGETRequest(c, "parameters/"+url.PathEscape(component)+"/"+url.PathEscape(vhost)+"/"+url.PathEscape(name))
	if err != nil {
		return nil, err
	}

	if err = executeAndParseRequest(c, req, &p); err != nil {
		return nil, err
	}

	return p, nil
}

//
// PUT /api/parameters/{component}/{vhost}/{name}
//

// PutRuntimeParameter creates or updates a runtime parameter.
func (c *Client) PutRuntimeParameter(component, vhost, name string, value interface{}) (res *http.Response, err error) {
	p := RuntimeParameter{
		Name:      name,
		Vhost:     vhost,
		Component: component,
		Value:     value,
	}

	body, err := json.Marshal(p)
	if err != nil {
		return nil, err
	}

	req, err := newRequestWithBody(c, "PUT", "parameters/"+url.PathEscape(component)+"/"+url.PathEscape(vhost)+"/"+url.PathEscape(name), body)
	if err != nil {
		return nil, err
	}

	if res, err = executeRequest(c, req); err != nil {
		return nil, err
	}

	return res, nil
}

//
// DELETE /api/parameters/{component}/{vhost}/{name}
//

// DeleteRuntimeParameter removes a runtime parameter.
func (c *Client) DeleteRuntimeParameter(component, vhost, name string) (res *http.Response, err error) {
	req, err := newRequestWithBody(c, "DELETE", "parameters/"+url.PathEscape(component)+"/"+url.PathEscape(vhost)+"/"+url.PathEscape(name), nil)
	if err != nil {
		return nil, err
	}

	if res, err = executeRequest(c, req); err != nil {
		return nil, err
	}

	return res, nil
}

// DeleteAllRuntimeParameters clears all runtime parameters. Only mean to be used
// in integration tests.
func (c *Client) DeleteAllRuntimeParameters() (err error) {
	list, err := c.ListRuntimeParameters()
	if err != nil {
		return err
	}

	for _, rp := range list {
		_, err = c.DeleteRuntimeParameter(rp.Component, rp.Vhost, rp.Name)
		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>add runtime definitions for rabbitmq<commit_after>package rabbithole

import (
	"encoding/json"
	"net/http"
	"net/url"
)

// RuntimeParameter represents a vhost-scoped parameter.
// Value is interface{} to support creating parameters directly from types such as
// FederationUpstream and ShovelInfo.
type RuntimeParameter struct {
	Name      string      `json:"name"`
	Vhost     string      `json:"vhost"`
	Component string      `json:"component"`
	Value     interface{} `json:"value"`
}

// RuntimeDefinitions represents rabbitmq runtime configuration.
type RuntimeDefinitions struct {
	RabbitVersion    string      `json:"rabbit_version"`
	RabbitmqVersion  string      `json:"rabbitmq_version"`
	ProductName      string      `json:"product_name"`
	ProductVersion   string      `json:"product_version"`
	Users            interface{} `json:"users"`
	Vhosts           interface{} `json:"vhosts"`
	Permissions      interface{} `json:"permissions"`
	TopicPermissions interface{} `json:"topic_permissions"`
	Parameters       interface{} `json:"parameters"`
	GlobalParameters interface{} `json:"global_parameters"`
	Policies         interface{} `json:"policies"`
	Queues           interface{} `json:"queues"`
	Exchanges        interface{} `json:"exchanges"`
	Bindings         interface{} `json:"bindings"`
}

// RuntimeParameterValue represents arbitrary parameter data.
type RuntimeParameterValue map[string]interface{}

//
// GET /api/definitions
//

func (c *Client) ListRuntimeDefinitions() (p *RuntimeDefinitions, err error) {
	req, err := newGETRequest(c, "definitions")
	if err != nil {
		return nil, err
	}

	if err = executeAndParseRequest(c, req, &p); err != nil {
		return nil, err
	}

	return p, nil
}

//
// GET /api/parameters
//

// ListRuntimeParameters returns a list of all runtime parameters.
func (c *Client) ListRuntimeParameters() (params []RuntimeParameter, err error) {
	req, err := newGETRequest(c, "parameters")
	if err != nil {
		return []RuntimeParameter{}, err
	}

	if err = executeAndParseRequest(c, req, &params); err != nil {
		return []RuntimeParameter{}, err
	}

	return params, nil
}

//
// GET /api/parameters/{component}
//

// ListRuntimeParametersFor returns a list of all runtime parameters for a component in all vhosts.
func (c *Client) ListRuntimeParametersFor(component string) (params []RuntimeParameter, err error) {
	req, err := newGETRequest(c, "parameters/"+url.PathEscape(component))
	if err != nil {
		return []RuntimeParameter{}, err
	}

	if err = executeAndParseRequest(c, req, &params); err != nil {
		return []RuntimeParameter{}, err
	}

	return params, nil
}

//
// GET /api/parameters/{component}/{vhost}
//

// ListRuntimeParametersIn returns a list of all runtime parameters for a component in a vhost.
func (c *Client) ListRuntimeParametersIn(component, vhost string) (p []RuntimeParameter, err error) {
	req, err := newGETRequest(c, "parameters/"+url.PathEscape(component)+"/"+url.PathEscape(vhost))
	if err != nil {
		return []RuntimeParameter{}, err
	}

	if err = executeAndParseRequest(c, req, &p); err != nil {
		return []RuntimeParameter{}, err
	}

	return p, nil
}

//
// GET /api/parameters/{component}/{vhost}/{name}
//

// GetRuntimeParameter returns information about a runtime parameter.
func (c *Client) GetRuntimeParameter(component, vhost, name string) (p *RuntimeParameter, err error) {
	req, err := newGETRequest(c, "parameters/"+url.PathEscape(component)+"/"+url.PathEscape(vhost)+"/"+url.PathEscape(name))
	if err != nil {
		return nil, err
	}

	if err = executeAndParseRequest(c, req, &p); err != nil {
		return nil, err
	}

	return p, nil
}

//
// PUT /api/parameters/{component}/{vhost}/{name}
//

// PutRuntimeParameter creates or updates a runtime parameter.
func (c *Client) PutRuntimeParameter(component, vhost, name string, value interface{}) (res *http.Response, err error) {
	p := RuntimeParameter{
		Name:      name,
		Vhost:     vhost,
		Component: component,
		Value:     value,
	}

	body, err := json.Marshal(p)
	if err != nil {
		return nil, err
	}

	req, err := newRequestWithBody(c, "PUT", "parameters/"+url.PathEscape(component)+"/"+url.PathEscape(vhost)+"/"+url.PathEscape(name), body)
	if err != nil {
		return nil, err
	}

	if res, err = executeRequest(c, req); err != nil {
		return nil, err
	}

	return res, nil
}

//
// DELETE /api/parameters/{component}/{vhost}/{name}
//

// DeleteRuntimeParameter removes a runtime parameter.
func (c *Client) DeleteRuntimeParameter(component, vhost, name string) (res *http.Response, err error) {
	req, err := newRequestWithBody(c, "DELETE", "parameters/"+url.PathEscape(component)+"/"+url.PathEscape(vhost)+"/"+url.PathEscape(name), nil)
	if err != nil {
		return nil, err
	}

	if res, err = executeRequest(c, req); err != nil {
		return nil, err
	}

	return res, nil
}

// DeleteAllRuntimeParameters clears all runtime parameters. Only mean to be used
// in integration tests.
func (c *Client) DeleteAllRuntimeParameters() (err error) {
	list, err := c.ListRuntimeParameters()
	if err != nil {
		return err
	}

	for _, rp := range list {
		_, err = c.DeleteRuntimeParameter(rp.Component, rp.Vhost, rp.Name)
		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package naked

import (
	"time"

	"github.com/sacloud/libsacloud-v2/sacloud/types"
)

// GSLB GSLB
type GSLB struct {
	ID           types.ID            `json:",omitempty" yaml:"id,omitempty" structs:",omitempty"`
	Name         string              `json:",omitempty" yaml:"name,omitempty" structs:",omitempty"`
	Description  string              `json:",omitempty" yaml:"description,omitempty" structs:",omitempty"`
	Tags         []string            `json:"" yaml:"tags"`
	Icon         *Icon               `json:",omitempty" yaml:"icon,omitempty" structs:",omitempty"`
	CreatedAt    *time.Time          `json:",omitempty" yaml:"created_at,omitempty" structs:",omitempty"`
	ModifiedAt   *time.Time          `json:",omitempty" yaml:"modified_at,omitempty" structs:",omitempty"`
	Availability types.EAvailability `json:",omitempty" yaml:"availability,omitempty" structs:",omitempty"`
	ServiceClass string              `json:",omitempty" yaml:"service_class,omitempty" structs:",omitempty"`
	Provider     *Provider           `json:",ommitempty" yaml:"provider,ommitempty" structs:",omitempty"`
	Settings     *GSLBSettings       `json:",ommitempty" yaml:"settings,ommitempty" structs:",omitempty"`
	SettingsHash string              `json:",ommitempty" yaml:"settings_hash,ommitempty" structs:",omitempty"`
	Status       *GSLBStatus         `json:",ommitempty" yaml:"status,ommitempty" structs:",omitempty"`
}

// GSLBSettings GSLBの設定
type GSLBSettings struct {
	GSLB *GSLBSetting `json:",omitempty" yaml:"gslb,omitempty" structs:",omitempty"`
}

// GSLBSetting GSLBの設定
type GSLBSetting struct {
	DelayLoop   int              `json:",omitemmpty" yaml:"delay_loop,omitempty" structs:",omitempty"`
	HealthCheck *GSLBHealthCheck `json:",omitemmpty" yaml:"health_check,omitempty" structs:",omitempty"`
	Weighted    types.StringFlag `json:",omitemmpty" yaml:"weighted,omitempty" structs:",omitempty"`
	Servers     []*GSLBServer    `yaml:"servers"`
	SorryServer string           `json:",omitempty" yaml:",omitempty" structs:",omitempty"` // ソーリーサーバー
}

// GSLBHealthCheck GSLBヘルスチェック
type GSLBHealthCheck struct {
	Protocol string             `json:",omitempty" yaml:"protocol,omitempty" structs:""` // プロトコル
	Host     string             `json:",omitempty" yaml:"host,omitempty" structs:""`     // 対象ホスト
	Path     string             `json:",omitempty" yaml:"path,omitempty" structs:""`     // HTTP/HTTPSの場合のリクエストパス
	Status   types.StringNumber `json:",omitempty" yaml:"status,omitempty" structs:""`   // 期待するステータスコード
	Port     types.StringNumber `json:",omitempty" yaml:"port,omitempty" structs:""`     // ポート番号
}

// GSLBServer GSLB配下のサーバー
type GSLBServer struct {
	IPAddress string             `json:",omitempty" yaml:"ip_address,omitempty" structs:",omitempty"` // IPアドレス
	Enabled   types.StringFlag   `json:",omitempty" yaml:"enabled,omitempty" structs:",omitempty"`    // 有効/無効
	Weight    types.StringNumber `json:",omitempty" yaml:"weight,omitempty" structs:",omitempty"`     // ウェイト
}

// GSLBStatus GSLBステータス
type GSLBStatus struct {
	FQDN string `json:",omitempty" yaml:"fqdn,omitempty" structs:",omitempty"`
}
<commit_msg>Fix struct tags<commit_after>package naked

import (
	"time"

	"github.com/sacloud/libsacloud-v2/sacloud/types"
)

// GSLB GSLB
type GSLB struct {
	ID           types.ID            `json:",omitempty" yaml:"id,omitempty" structs:",omitempty"`
	Name         string              `json:",omitempty" yaml:"name,omitempty" structs:",omitempty"`
	Description  string              `json:",omitempty" yaml:"description,omitempty" structs:",omitempty"`
	Tags         []string            `json:"" yaml:"tags"`
	Icon         *Icon               `json:",omitempty" yaml:"icon,omitempty" structs:",omitempty"`
	CreatedAt    *time.Time          `json:",omitempty" yaml:"created_at,omitempty" structs:",omitempty"`
	ModifiedAt   *time.Time          `json:",omitempty" yaml:"modified_at,omitempty" structs:",omitempty"`
	Availability types.EAvailability `json:",omitempty" yaml:"availability,omitempty" structs:",omitempty"`
	ServiceClass string              `json:",omitempty" yaml:"service_class,omitempty" structs:",omitempty"`
	Provider     *Provider           `json:",ommitempty" yaml:"provider,ommitempty" structs:",omitempty"`
	Settings     *GSLBSettings       `json:",ommitempty" yaml:"settings,ommitempty" structs:",omitempty"`
	SettingsHash string              `json:",ommitempty" yaml:"settings_hash,ommitempty" structs:",omitempty"`
	Status       *GSLBStatus         `json:",ommitempty" yaml:"status,ommitempty" structs:",omitempty"`
}

// GSLBSettings GSLBの設定
type GSLBSettings struct {
	GSLB *GSLBSetting `json:",omitempty" yaml:"gslb,omitempty" structs:",omitempty"`
}

// GSLBSetting GSLBの設定
type GSLBSetting struct {
	DelayLoop   int              `json:",omitemmpty" yaml:"delay_loop,omitempty" structs:",omitempty"`
	HealthCheck *GSLBHealthCheck `json:",omitemmpty" yaml:"health_check,omitempty" structs:",omitempty"`
	Weighted    types.StringFlag `yaml:"weighted"`
	Servers     []*GSLBServer    `yaml:"servers"`
	SorryServer string           `json:",omitempty" yaml:",omitempty" structs:",omitempty"` // ソーリーサーバー
}

// GSLBHealthCheck GSLBヘルスチェック
type GSLBHealthCheck struct {
	Protocol string             `json:",omitempty" yaml:"protocol,omitempty" structs:""` // プロトコル
	Host     string             `json:",omitempty" yaml:"host,omitempty" structs:""`     // 対象ホスト
	Path     string             `json:",omitempty" yaml:"path,omitempty" structs:""`     // HTTP/HTTPSの場合のリクエストパス
	Status   types.StringNumber `json:",omitempty" yaml:"status,omitempty" structs:""`   // 期待するステータスコード
	Port     types.StringNumber `json:",omitempty" yaml:"port,omitempty" structs:""`     // ポート番号
}

// GSLBServer GSLB配下のサーバー
type GSLBServer struct {
	IPAddress string             `json:",omitempty" yaml:"ip_address,omitempty" structs:",omitempty"` // IPアドレス
	Enabled   types.StringFlag   `yaml:"enabled" `                                                    // 有効/無効
	Weight    types.StringNumber `json:",omitempty" yaml:"weight,omitempty" structs:",omitempty"`     // ウェイト
}

// GSLBStatus GSLBステータス
type GSLBStatus struct {
	FQDN string `json:",omitempty" yaml:"fqdn,omitempty" structs:",omitempty"`
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"log"
	"net"
	"sync/atomic"
	"time"

	"github.com/yinqiwen/gotoolkit/ots"
	"github.com/yinqiwen/gsnova/common/event"
	"github.com/yinqiwen/gsnova/remote"
)

var totalConn int32

func serveProxyConn(conn net.Conn) {
	atomic.AddInt32(&totalConn, 1)
	bufconn := bufio.NewReader(conn)

	deferFunc := func() {
		conn.Close()
		atomic.AddInt32(&totalConn, -1)
	}
	defer deferFunc()

	ctx := remote.NewConnContext()

	writeEvent := func(ev event.Event) error {
		var buf bytes.Buffer
		event.EncryptEvent(&buf, ev, ctx.IV)
		conn.SetWriteDeadline(time.Now().Add(5 * time.Second))
		_, err := conn.Write(buf.Bytes())
		return err
	}

	var buf bytes.Buffer
	b := make([]byte, 8192)

	var queue *event.EventQueue
	connClosed := false
	for !connClosed {
		conn.SetReadDeadline(time.Now().Add(60 * time.Second))
		n, cerr := bufconn.Read(b)
		if n > 0 {
			buf.Write(b[0:n])
		}
		if nil != cerr {
			conn.Close()
			connClosed = true
		}
		ress, err := remote.HandleRequestBuffer(&buf, ctx)
		if nil != err {
			if err != event.EBNR {
				log.Printf("[ERROR]connection %s:%d error:%v", ctx.User, ctx.ConnIndex, err)
				conn.Close()
				connClosed = true
				return
			}
		} else {
			for _, res := range ress {
				writeEvent(res)
			}
			if nil == queue && len(ctx.User) > 0 && ctx.ConnIndex >= 0 {
				queue = remote.GetEventQueue(ctx.ConnId, true)
				go func() {
					var lastEventTime time.Time
					for !connClosed {
						ev, err := queue.Peek(1 * time.Millisecond)
						if nil != err {
							if GetSessionTableSize() > 0 && lastEventTime.Add(5*time.Second).Before(time.Now()) {
								ev = &event.HeartBeatEvent{}
							} else {
								continue
							}
						}

						err = writeEvent(ev)
						lastEventTime = time.Now()
						if nil != err {
							log.Printf("TCP write error:%v", err)
							conn.Close()
							return
						} else {
							queue.ReadPeek()
						}
					}
				}()
			}
		}
	}
}

func startLocalProxyServer(addr string) error {
	if len(addr) == 0 {
		log.Fatalf("Empty listen address.")
		return nil
	}
	tcpaddr, err := net.ResolveTCPAddr("tcp", addr)
	if nil != err {
		log.Fatalf("[ERROR]Local server address:%s error:%v", addr, err)
		return err
	}
	var lp *net.TCPListener
	lp, err = net.ListenTCP("tcp", tcpaddr)
	if nil != err {
		log.Fatalf("Can NOT listen on address:%s", addr)
		return err
	}
	log.Printf("Listen on address %s", addr)
	for {
		conn, err := lp.AcceptTCP()
		if nil != err {
			continue
		}
		go serveProxyConn(conn)
	}
	return nil
}

func dumpServerStat(args []string, c io.Writer) error {
	fmt.Fprintf(c, "NumSession:    %d\n", remote.GetSessionTableSize())
	fmt.Fprintf(c, "TotalUserConn: %d\n", totalConn)
	return nil
}

func main() {
	ots.RegisterHandler("vstat", dumpServerStat, 0, 0, "VStat                                 Dump server stat")
	err := ots.StartTroubleShootingServer(remote.ServerConf.AdminListen)
	if nil != err {
		log.Printf("Failed to start admin server with reason:%v", err)
		return
	}
	startLocalProxyServer(remote.ServerConf.Listen)
}
<commit_msg>update remote<commit_after>package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"log"
	"net"
	"sync/atomic"
	"time"

	"github.com/yinqiwen/gotoolkit/ots"
	"github.com/yinqiwen/gsnova/common/event"
	"github.com/yinqiwen/gsnova/remote"
)

var totalConn int32

func serveProxyConn(conn net.Conn) {
	atomic.AddInt32(&totalConn, 1)
	bufconn := bufio.NewReader(conn)

	deferFunc := func() {
		conn.Close()
		atomic.AddInt32(&totalConn, -1)
	}
	defer deferFunc()

	ctx := remote.NewConnContext()

	writeEvent := func(ev event.Event) error {
		var buf bytes.Buffer
		event.EncryptEvent(&buf, ev, ctx.IV)
		conn.SetWriteDeadline(time.Now().Add(5 * time.Second))
		_, err := conn.Write(buf.Bytes())
		return err
	}

	var buf bytes.Buffer
	b := make([]byte, 8192)

	var queue *event.EventQueue
	connClosed := false
	for !connClosed {
		conn.SetReadDeadline(time.Now().Add(60 * time.Second))
		n, cerr := bufconn.Read(b)
		if n > 0 {
			buf.Write(b[0:n])
		}
		if nil != cerr {
			conn.Close()
			connClosed = true
		}
		ress, err := remote.HandleRequestBuffer(&buf, ctx)
		if nil != err {
			if err != event.EBNR {
				log.Printf("[ERROR]connection %s:%d error:%v", ctx.User, ctx.ConnIndex, err)
				conn.Close()
				connClosed = true
				return
			}
		} else {
			for _, res := range ress {
				writeEvent(res)
			}
			if nil == queue && len(ctx.User) > 0 && ctx.ConnIndex >= 0 {
				queue = remote.GetEventQueue(ctx.ConnId, true)
				go func() {
					var lastEventTime time.Time
					for !connClosed {
						ev, err := queue.Peek(1 * time.Millisecond)
						if nil != err {
							if remote.GetSessionTableSize() > 0 && lastEventTime.Add(5*time.Second).Before(time.Now()) {
								ev = &event.HeartBeatEvent{}
							} else {
								continue
							}
						}

						err = writeEvent(ev)
						lastEventTime = time.Now()
						if nil != err {
							log.Printf("TCP write error:%v", err)
							conn.Close()
							return
						} else {
							queue.ReadPeek()
						}
					}
				}()
			}
		}
	}
}

func startLocalProxyServer(addr string) error {
	if len(addr) == 0 {
		log.Fatalf("Empty listen address.")
		return nil
	}
	tcpaddr, err := net.ResolveTCPAddr("tcp", addr)
	if nil != err {
		log.Fatalf("[ERROR]Local server address:%s error:%v", addr, err)
		return err
	}
	var lp *net.TCPListener
	lp, err = net.ListenTCP("tcp", tcpaddr)
	if nil != err {
		log.Fatalf("Can NOT listen on address:%s", addr)
		return err
	}
	log.Printf("Listen on address %s", addr)
	for {
		conn, err := lp.AcceptTCP()
		if nil != err {
			continue
		}
		go serveProxyConn(conn)
	}
	return nil
}

func dumpServerStat(args []string, c io.Writer) error {
	fmt.Fprintf(c, "NumSession:    %d\n", remote.GetSessionTableSize())
	fmt.Fprintf(c, "TotalUserConn: %d\n", totalConn)
	return nil
}

func main() {
	ots.RegisterHandler("vstat", dumpServerStat, 0, 0, "VStat                                 Dump server stat")
	err := ots.StartTroubleShootingServer(remote.ServerConf.AdminListen)
	if nil != err {
		log.Printf("Failed to start admin server with reason:%v", err)
		return
	}
	startLocalProxyServer(remote.ServerConf.Listen)
}
<|endoftext|>