<commit_before>/*
Copyright © 2014–5 Brad Ackerman.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

package api

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strconv"

	"github.com/backerman/evego"
	"github.com/backerman/eveindy/pkg/db"
	"github.com/backerman/eveindy/pkg/server"
	"github.com/zenazn/goji/web"
)

// unmarshalKey attempts to unmarshal an XML api key as passed by the client.
// It returns the key iff successful, or a non-nil error otherwise.
func unmarshalKey(r *http.Request, w http.ResponseWriter) (*db.XMLAPIKey, error) {
	keyJSON, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Unable to read key", http.StatusBadRequest)
		w.Write([]byte(`{"status": "Error"}`))
		return nil, err
	}
	key := db.XMLAPIKey{}
	err = json.Unmarshal(keyJSON, &key)
	if err != nil {
		http.Error(w, "Unable to unmarshal key", http.StatusBadRequest)
		w.Write([]byte(`{"status": "Error"}`))
		return nil, err
	}
	return &key, nil
}

// XMLAPIKeysHandlers returns web handler functions that provide information on
// the user's API keys that have been registered with this application.
func XMLAPIKeysHandlers(localdb db.LocalDB, sess server.Sessionizer) (list, delete, add, refresh web.HandlerFunc) {
	// charRefresh refreshes the characters associated with an API key and returns
	// the current list of characters via the passed responseWriter.
	charRefresh := func(s *db.Session, key *db.XMLAPIKey, w http.ResponseWriter) {
		toons, err := localdb.GetAPICharacters(s.User, *key)
		if err != nil {
			http.Error(w, "Database connection error (add characters)", http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		response := struct {
			Status     string            `json:"status"`
			Characters []evego.Character `json:"characters"`
		}{
			Status:     "OK",
			Characters: toons,
		}
		responseJSON, err := json.Marshal(response)
		w.Write(responseJSON)
		return
	}

	list = func(c web.C, w http.ResponseWriter, r *http.Request) {
		s := sess.GetSession(&c, w, r)
		userKeys, err := localdb.APIKeys(s.User)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		userKeysJSON, err := json.Marshal(userKeys)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		w.Write(userKeysJSON)
	}

	delete = func(c web.C, w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "This function must be called with the POST method",
				http.StatusMethodNotAllowed)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		s := sess.GetSession(&c, w, r)
		keyID, _ := strconv.Atoi(c.URLParams["keyid"])
		err := localdb.DeleteAPIKey(s.User, keyID)
		if err != nil {
			http.Error(w, "Database connection error", http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		w.Write([]byte(`{"status": "OK"}`))
		return
	}

	add = func(c web.C, w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "This function must be called with the POST method",
				http.StatusMethodNotAllowed)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		s := sess.GetSession(&c, w, r)
		key, err := unmarshalKey(r, w)
		if err != nil {
			return
		}
		// Ensure that this key is added under the session's user's account.
		key.User = s.User

		err = localdb.AddAPIKey(*key)
		if err != nil {
			http.Error(w, "Database connection error (add key)", http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}

		charRefresh(s, key, w)
		return
	}

	refresh = func(c web.C, w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "This function must be called with the POST method",
				http.StatusMethodNotAllowed)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		s := sess.GetSession(&c, w, r)
		key, err := unmarshalKey(r, w)
		if err != nil {
			return
		}

		// Ensure that this key is added under the session's user's account.
		key.User = s.User
		charRefresh(s, key, w)
		return
	}

	return
}
<commit_msg>Update skills when refreshing API.<commit_after>/*
Copyright © 2014–5 Brad Ackerman.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

package api

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
	"strconv"

	"github.com/backerman/evego"
	"github.com/backerman/eveindy/pkg/db"
	"github.com/backerman/eveindy/pkg/server"
	"github.com/zenazn/goji/web"
)

// unmarshalKey attempts to unmarshal an XML api key as passed by the client.
// It returns the key iff successful, or a non-nil error otherwise.
func unmarshalKey(r *http.Request, w http.ResponseWriter) (*db.XMLAPIKey, error) {
	keyJSON, err := ioutil.ReadAll(r.Body)
	if err != nil {
		http.Error(w, "Unable to read key", http.StatusBadRequest)
		w.Write([]byte(`{"status": "Error"}`))
		return nil, err
	}
	key := db.XMLAPIKey{}
	err = json.Unmarshal(keyJSON, &key)
	if err != nil {
		http.Error(w, "Unable to unmarshal key", http.StatusBadRequest)
		w.Write([]byte(`{"status": "Error"}`))
		return nil, err
	}
	return &key, nil
}

// XMLAPIKeysHandlers returns web handler functions that provide information on
// the user's API keys that have been registered with this application.
func XMLAPIKeysHandlers(localdb db.LocalDB, sess server.Sessionizer) (list, delete, add, refresh web.HandlerFunc) {
	// charRefresh refreshes the characters associated with an API key and returns
	// the current list of characters via the passed responseWriter.
	charRefresh := func(s *db.Session, key *db.XMLAPIKey, w http.ResponseWriter) {
		toons, err := localdb.GetAPICharacters(s.User, *key)
		if err != nil {
			http.Error(w, "Database connection error (add characters)", http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		for _, toon := range toons {
			// Update skills for this character.
			err = localdb.GetAPISkills(*key, toon.ID)
			if err != nil {
				http.Error(w, "Database connection error (add skills)", http.StatusInternalServerError)
				w.Write([]byte(`{"status": "Error"}`))
				return
			}
		}
		response := struct {
			Status     string            `json:"status"`
			Characters []evego.Character `json:"characters"`
		}{
			Status:     "OK",
			Characters: toons,
		}
		responseJSON, err := json.Marshal(response)
		w.Write(responseJSON)
		return
	}

	list = func(c web.C, w http.ResponseWriter, r *http.Request) {
		s := sess.GetSession(&c, w, r)
		userKeys, err := localdb.APIKeys(s.User)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		userKeysJSON, err := json.Marshal(userKeys)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		w.Write(userKeysJSON)
	}

	delete = func(c web.C, w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "This function must be called with the POST method",
				http.StatusMethodNotAllowed)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		s := sess.GetSession(&c, w, r)
		keyID, _ := strconv.Atoi(c.URLParams["keyid"])
		err := localdb.DeleteAPIKey(s.User, keyID)
		if err != nil {
			http.Error(w, "Database connection error", http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		w.Write([]byte(`{"status": "OK"}`))
		return
	}

	add = func(c web.C, w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "This function must be called with the POST method",
				http.StatusMethodNotAllowed)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		s := sess.GetSession(&c, w, r)
		key, err := unmarshalKey(r, w)
		if err != nil {
			return
		}
		// Ensure that this key is added under the session's user's account.
		key.User = s.User

		err = localdb.AddAPIKey(*key)
		if err != nil {
			http.Error(w, "Database connection error (add key)", http.StatusInternalServerError)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}

		charRefresh(s, key, w)
		return
	}

	refresh = func(c web.C, w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "This function must be called with the POST method",
				http.StatusMethodNotAllowed)
			w.Write([]byte(`{"status": "Error"}`))
			return
		}
		s := sess.GetSession(&c, w, r)
		key, err := unmarshalKey(r, w)
		if err != nil {
			return
		}

		// Ensure that this key is added under the session's user's account.
		key.User = s.User
		charRefresh(s, key, w)
		return
	}

	return
}
<|endoftext|>


<commit_before>package build

import (
	"crypto/md5"
	"crypto/sha256"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
)

func logAndClose(c io.Closer) {
	if err := c.Close(); err != nil {
		log.Println("error closing:", err)
	}
}

func shaDir(dir string) error {
	return filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
		if path == dir {
			return nil
		}

		if strings.Contains(path, ".sha256") {
			return nil
		}
		if err := shaFile(path); err != nil {
			log.Printf("Failed to create sha file. error: %v\n", err)
		}
		return nil
	})
}

func shaFile(file string) error {
	// Can ignore gosec G304 because this function is not used in Grafana, only in the build process.
	//nolint:gosec
	r, err := os.Open(file)
	if err != nil {
		return err
	}

	defer logAndClose(r)

	h := sha256.New()
	_, err = io.Copy(h, r)
	if err != nil {
		return err
	}

	out, err := os.Create(file + ".sha256")
	if err != nil {
		return err
	}

	_, err = fmt.Fprintf(out, "%x\n", h.Sum(nil))
	if err != nil {
		return err
	}

	return out.Close()
}

func md5File(file string) error {
	// Can ignore gosec G304 because this function is not used in Grafana, only in the build process.
	//nolint:gosec
	fd, err := os.Open(file)
	if err != nil {
		return err
	}
	defer logAndClose(fd)

	h := md5.New()
	_, err = io.Copy(h, fd)
	if err != nil {
		return err
	}

	out, err := os.Create(file + ".md5")
	if err != nil {
		return err
	}

	_, err = fmt.Fprintf(out, "%x\n", h.Sum(nil))
	if err != nil {
		return err
	}

	return out.Close()
}

// basically `rm -r`s the list of files provided
func rmr(paths ...string) {
	for _, path := range paths {
		log.Println("rm -r", path)
		if err := os.RemoveAll(path); err != nil {
			log.Println("error deleting folder", path, "error:", err)
		}
	}
}
<commit_msg>Add nolint to two lines in fs.go (#49357)<commit_after>package build

import (
	"crypto/md5"
	"crypto/sha256"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
)

func logAndClose(c io.Closer) {
	if err := c.Close(); err != nil {
		log.Println("error closing:", err)
	}
}

func shaDir(dir string) error {
	return filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
		if path == dir {
			return nil
		}

		if strings.Contains(path, ".sha256") {
			return nil
		}
		if err := shaFile(path); err != nil {
			log.Printf("Failed to create sha file. error: %v\n", err)
		}
		return nil
	})
}

func shaFile(file string) error {
	// Ignore gosec G304 as this function is only used in the build process.
	//nolint:gosec
	r, err := os.Open(file)
	if err != nil {
		return err
	}

	defer logAndClose(r)

	h := sha256.New()
	_, err = io.Copy(h, r)
	if err != nil {
		return err
	}

	// Ignore gosec G304 as this function is only used in the build process.
	//nolint:gosec
	out, err := os.Create(file + ".sha256")
	if err != nil {
		return err
	}

	_, err = fmt.Fprintf(out, "%x\n", h.Sum(nil))
	if err != nil {
		return err
	}

	return out.Close()
}

func md5File(file string) error {
	// Ignore gosec G304 as this function is only used in the build process.
	//nolint:gosec
	fd, err := os.Open(file)
	if err != nil {
		return err
	}
	defer logAndClose(fd)

	h := md5.New()
	_, err = io.Copy(h, fd)
	if err != nil {
		return err
	}

	// Ignore gosec G304 as this function is only used in the build process.
	//nolint:gosec
	out, err := os.Create(file + ".md5")
	if err != nil {
		return err
	}

	_, err = fmt.Fprintf(out, "%x\n", h.Sum(nil))
	if err != nil {
		return err
	}

	return out.Close()
}

// basically `rm -r`s the list of files provided
func rmr(paths ...string) {
	for _, path := range paths {
		log.Println("rm -r", path)
		if err := os.RemoveAll(path); err != nil {
			log.Println("error deleting folder", path, "error:", err)
		}
	}
}
<|endoftext|>


<commit_before>package chat

import (
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
)

// Ingest a ThreadView, check several invariants, and produce a list of prev
// pointers to not-yet-pointed-to messages. Check several invariants at the
// same time:
// 1. No two messages have the same ID.
// 2. All prev pointers point to messages with lesser IDs.
// 3. All prev pointers to a message agree on that message's header hash.
// 4. For all messages we have locally, the hashes pointing to them are actually correct.
// TODO: All of this should happen in the cache instead of here all at once.
func CheckPrevPointersAndGetUnpreved(thread *chat1.ThreadView) ([]chat1.MessagePreviousPointer, libkb.ChatThreadConsistencyError) {
	// Filter out the messages that gave unboxing errors, and index the rest by
	// ID. Enforce that there are no duplicate IDs.
	// TODO: What should we really be doing with unboxing errors? Do we worry
	//       about an evil server causing them intentionally?
	knownMessages := make(map[chat1.MessageID]chat1.MessageUnboxedValid)
	unprevedIDs := make(map[chat1.MessageID]struct{})
	for _, messageOrError := range thread.Messages {
		if messageOrError.IsValid() {
			msg := messageOrError.Valid()
			id := msg.ServerHeader.MessageID

			// Check for IDs that show up more than once. IDs are assigned
			// sequentially by the server, so this should really never happen.
			_, alreadyExists := knownMessages[id]
			if alreadyExists {
				return nil, libkb.NewChatThreadConsistencyError(
					libkb.DuplicateID,
					"MessageID %d is duplicated",
					id)
			}

			knownMessages[id] = msg
			unprevedIDs[id] = struct{}{}
		}
	}

	// Using the index we built above, check each prev pointer on each message
	// to make sure its hash is correct. Some prev pointers might refer to
	// messages we don't have locally, and in that case we just check that all
	// prev pointers to that message are *consistent*. While we're at it, also
	// enforce that each prev's ID is less than the ID of the message that's
	// pointing to it.
	seenHashes := make(map[chat1.MessageID]chat1.Hash)
	for id, msg := range knownMessages {
		for _, prev := range msg.ClientHeader.Prev {
			// Check that the prev's ID doesn't come after us. That would make no sense.
			if prev.Id > id {
				return nil, libkb.NewChatThreadConsistencyError(
					libkb.OutOfOrderID,
					"MessageID %d thinks that message %d is previous.",
					id,
					prev.Id)
			}

			// If this message has been referred to before, check that it's
			// always referred to with the same hash.
			seenHash := seenHashes[prev.Id]
			if seenHash != nil {
				// We have seen it before! It's an error if it's different now.
				if !seenHash.Eq(prev.Hash) {
					return nil, libkb.NewChatThreadConsistencyError(
						libkb.InconsistentHash,
						"MessageID %d has an inconsistent hash for ID %d (%s and %s)",
						id, prev.Id, prev.Hash.String(), seenHash.String())
				}
			} else {
				// We haven't seen it before. Save it.
				seenHashes[prev.Id] = prev.Hash
				// And if we do have the previous message in memory, make sure
				// that what we're saving matches the actual hash for the
				// message. (Note that HeaderHash is computed *locally* at unbox
				// time; we're not taking anyone's word for it.)
				prevMessage, weHaveIt := knownMessages[prev.Id]
				if weHaveIt && !prevMessage.HeaderHash.Eq(prev.Hash) {
					return nil, libkb.NewChatThreadConsistencyError(
						libkb.IncorrectHash,
						"Message ID %d thinks message ID %d should have hash %s, but it has %s.",
						id, prev.Id, prev.Hash.String(), prevMessage.HeaderHash.String())
				}
				// Also remove this message from the set of "never been pointed
				// to".
				delete(unprevedIDs, prev.Id)
			}
		}
	}

	newPrevs := []chat1.MessagePreviousPointer{}
	for id := range unprevedIDs {
		newPrevs = append(newPrevs, chat1.MessagePreviousPointer{
			Id:   id,
			Hash: knownMessages[id].HeaderHash,
		})
	}

	return newPrevs, nil
}
<commit_msg>clean up prev.go<commit_after>package chat

import (
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
)

// Ingest a ThreadView, check several invariants, and produce a list of prev
// pointers to not-yet-pointed-to messages. Check several invariants at the
// same time:
// 1. No two messages have the same ID.
// 2. All prev pointers point to messages with lesser IDs.
// 3. All prev pointers to a message agree on that message's header hash.
// 4. For all messages we have locally, the hashes pointing to them are actually correct.
// TODO: All of this should happen in the cache instead of here all at once.
func CheckPrevPointersAndGetUnpreved(thread *chat1.ThreadView) ([]chat1.MessagePreviousPointer, libkb.ChatThreadConsistencyError) {
	// Filter out the messages that gave unboxing errors, and index the rest by
	// ID. Enforce that there are no duplicate IDs or absurd prev pointers.
	// TODO: What should we really be doing with unboxing errors? Do we worry
	//       about an evil server causing them intentionally?
	knownMessages := make(map[chat1.MessageID]chat1.MessageUnboxedValid)
	unprevedIDs := make(map[chat1.MessageID]struct{})
	for _, messageOrError := range thread.Messages {
		if messageOrError.IsValid() {
			msg := messageOrError.Valid()
			id := msg.ServerHeader.MessageID

			// Check for IDs that show up more than once. IDs are assigned
			// sequentially by the server, so this should really never happen.
			_, alreadyExists := knownMessages[id]
			if alreadyExists {
				return nil, libkb.NewChatThreadConsistencyError(
					libkb.DuplicateID,
					"MessageID %d is duplicated",
					id)
			}

			// Check that each prev pointer (if any) is a lower ID than the
			// message itself.
			for _, prev := range msg.ClientHeader.Prev {
				if prev.Id > id {
					return nil, libkb.NewChatThreadConsistencyError(
						libkb.OutOfOrderID,
						"MessageID %d thinks that message %d is previous.",
						id,
						prev.Id)
				}
			}

			knownMessages[id] = msg
			unprevedIDs[id] = struct{}{}
		}
	}

	// Using the index we built above, check each prev pointer on each message
	// to make sure its hash is correct. Some prev pointers might refer to
	// messages we don't have locally, and in that case we just check that all
	// prev pointers to that message are *consistent*.
	seenHashes := make(map[chat1.MessageID]chat1.Hash)
	for id, msg := range knownMessages {
		for _, prev := range msg.ClientHeader.Prev {
			// If this message has been referred to before, check that it's
			// always referred to with the same hash.
			seenHash := seenHashes[prev.Id]
			if seenHash != nil {
				// We have seen it before! It's an error if it's different now.
				if !seenHash.Eq(prev.Hash) {
					return nil, libkb.NewChatThreadConsistencyError(
						libkb.InconsistentHash,
						"MessageID %d has an inconsistent hash for ID %d (%s and %s)",
						id, prev.Id, prev.Hash.String(), seenHash.String())
				}
			} else {
				// We haven't seen it before. Save it.
				seenHashes[prev.Id] = prev.Hash
				// And if we do have the previous message in memory, make sure
				// that what we're saving matches the actual hash for the
				// message. (Note that HeaderHash is computed *locally* at unbox
				// time; we're not taking anyone's word for it.)
				prevMessage, weHaveIt := knownMessages[prev.Id]
				if weHaveIt && !prevMessage.HeaderHash.Eq(prev.Hash) {
					return nil, libkb.NewChatThreadConsistencyError(
						libkb.IncorrectHash,
						"Message ID %d thinks message ID %d should have hash %s, but it has %s.",
						id, prev.Id, prev.Hash.String(), prevMessage.HeaderHash.String())
				}
				// Also remove this message from the set of "never been pointed
				// to".
				delete(unprevedIDs, prev.Id)
			}
		}
	}

	newPrevs := []chat1.MessagePreviousPointer{}
	for id := range unprevedIDs {
		newPrevs = append(newPrevs, chat1.MessagePreviousPointer{
			Id:   id,
			Hash: knownMessages[id].HeaderHash,
		})
	}

	return newPrevs, nil
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package goapp

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"appengine/datastore"
	"appengine/urlfetch"
	"appengine/user"
	mpg "github.com/MiniProfiler/go/miniprofiler_gae"
	"github.com/mjibson/goon"
)

// parent: User, key: 1
type UserCharge struct {
	_kind  string         `goon:"kind,UC"`
	Id     int64          `datastore:"-" goon:"id"`
	Parent *datastore.Key `datastore:"-" goon:"parent"`

	Customer string    `datastore:"c,noindex json:"-"`
	Created  time.Time `datastore:"r,noindex"`
	Last4    string    `datastore:"l,noindex" json:"-"`
}

type StripeCustomer struct {
	Id      string      `json:"id"`
	Created int64       `json:"created"`
	Card    *StripeCard `json:"active_card"`
}

type StripeCard struct {
	Last4 string `json:"last4"`
}

func Charge(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	u := User{Id: cu.ID}
	uc := UserCharge{Id: 1, Parent: gn.Key(&u)}
	if err := gn.Get(&u); err != nil {
		serveError(w, err)
		return
	} else if u.Account != AFree {
		serveError(w, fmt.Errorf("You're already subscribed."))
		return
	}
	if err := gn.Get(&uc); err == nil && len(uc.Customer) > 0 {
		serveError(w, fmt.Errorf("You're already subscribed."))
		return
	} else if err != datastore.ErrNoSuchEntity {
		serveError(w, err)
		return
	}
	resp, err := stripe(c, "POST", "customers", url.Values{
		"email":       {u.Email},
		"description": {u.Id},
		"card":        {r.FormValue("stripeToken")},
		"plan":        {STRIPE_PLAN},
	}.Encode())
	if err != nil {
		serveError(w, err)
		return
	} else if resp.StatusCode != http.StatusOK {
		serveError(w, fmt.Errorf("Error"))
		return
	}
	defer resp.Body.Close()
	b, _ := ioutil.ReadAll(resp.Body)
	var sc StripeCustomer
	if err := json.Unmarshal(b, &sc); err != nil {
		serveError(w, err)
		return
	}
	if err := gn.RunInTransaction(func(gn *goon.Goon) error {
		if err := gn.Get(&u); err != nil && err != datastore.ErrNoSuchEntity {
			return err
		}
		if err := gn.Get(&uc); err != nil && err != datastore.ErrNoSuchEntity {
			return err
		}
		u.Account = APaid
		uc.Customer = sc.Id
		uc.Last4 = sc.Card.Last4
		uc.Created = time.Unix(sc.Created, 0)
		_, err := gn.PutMany(&u, &uc)
		return err
	}, nil); err != nil {
		serveError(w, err)
		return
	}
	b, _ = json.Marshal(&uc)
	w.Write(b)
}

func Account(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	u := User{Id: cu.ID}
	uc := UserCharge{Id: 1, Parent: gn.Key(&u)}
	if err := gn.Get(&uc); err == nil {
		b, _ := json.Marshal(&uc)
		w.Write(b)
	} else if err != datastore.ErrNoSuchEntity {
		serveError(w, err)
		return
	}
}

func Uncheckout(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	u := User{Id: cu.ID}
	uc := UserCharge{Id: 1, Parent: gn.Key(&u)}
	if err := gn.Get(&u); err != nil {
		serveError(w, err)
		return
	}
	if err := gn.Get(&uc); err != nil || len(uc.Customer) == 0 {
		serveError(w, err)
		return
	}
	resp, err := stripe(c, "DELETE", "customers/"+uc.Customer, "")
	if err != nil {
		serveError(w, err)
		return
	} else if resp.StatusCode != http.StatusOK {
		serveError(w, fmt.Errorf("Error"))
		return
	}
	if err := gn.RunInTransaction(func(gn *goon.Goon) error {
		if err := gn.Get(&u); err != nil && err != datastore.ErrNoSuchEntity {
			return err
		}
		u.Account = AFree
		if err := gn.Delete(gn.Key(&uc)); err != nil {
			return err
		}
		_, err := gn.Put(&u)
		return err
	}, nil); err != nil {
		serveError(w, err)
		return
	}
	b, _ := json.Marshal(&uc)
	w.Write(b)
}

func stripe(c mpg.Context, method, urlStr, body string) (*http.Response, error) {
	cl := &http.Client{
		Transport: &urlfetch.Transport{
			Context:  c,
			Deadline: time.Minute,
		},
	}
	req, err := http.NewRequest(method, fmt.Sprintf("https://api.stripe.com/v1/%s", urlStr), strings.NewReader(body))
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(STRIPE_SECRET, "")
	return cl.Do(req)
}

func Donate(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	u := User{Id: cu.ID}
	if err := gn.Get(&u); err != nil {
		serveError(w, err)
		return
	}
	amount, err := strconv.Atoi(r.FormValue("amount"))
	if err != nil || amount < 200 {
		serveError(w, fmt.Errorf("bad amount: %v", r.FormValue("amount")))
		return
	}
	resp, err := stripe(c, "POST", "charges", url.Values{
		"amount":      {r.FormValue("amount")},
		"description": {fmt.Sprintf("%v - %v", u.Id, u.Email)},
		"card":        {r.FormValue("stripeToken")},
		"currency":    {"usd"},
	}.Encode())
	if err != nil {
		serveError(w, err)
		return
	} else if resp.StatusCode != http.StatusOK {
		c.Errorf("%s", resp.Body)
		serveError(w, fmt.Errorf("Error"))
		return
	}
}
<commit_msg>Log stripe errors<commit_after>/*
 * Copyright (c) 2013 Matt Jibson <matt.jibson@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package goapp

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"

	"appengine/datastore"
	"appengine/urlfetch"
	"appengine/user"
	mpg "github.com/MiniProfiler/go/miniprofiler_gae"
	"github.com/mjibson/goon"
)

// parent: User, key: 1
type UserCharge struct {
	_kind  string         `goon:"kind,UC"`
	Id     int64          `datastore:"-" goon:"id"`
	Parent *datastore.Key `datastore:"-" goon:"parent"`

	Customer string    `datastore:"c,noindex json:"-"`
	Created  time.Time `datastore:"r,noindex"`
	Last4    string    `datastore:"l,noindex" json:"-"`
}

type StripeCustomer struct {
	Id      string      `json:"id"`
	Created int64       `json:"created"`
	Card    *StripeCard `json:"active_card"`
}

type StripeCard struct {
	Last4 string `json:"last4"`
}

func Charge(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	u := User{Id: cu.ID}
	uc := UserCharge{Id: 1, Parent: gn.Key(&u)}
	if err := gn.Get(&u); err != nil {
		serveError(w, err)
		return
	} else if u.Account != AFree {
		serveError(w, fmt.Errorf("You're already subscribed."))
		return
	}
	if err := gn.Get(&uc); err == nil && len(uc.Customer) > 0 {
		serveError(w, fmt.Errorf("You're already subscribed."))
		return
	} else if err != datastore.ErrNoSuchEntity {
		serveError(w, err)
		return
	}
	resp, err := stripe(c, "POST", "customers", url.Values{
		"email":       {u.Email},
		"description": {u.Id},
		"card":        {r.FormValue("stripeToken")},
		"plan":        {STRIPE_PLAN},
	}.Encode())
	if err != nil {
		serveError(w, err)
		return
	} else if resp.StatusCode != http.StatusOK {
		c.Errorf("%s", resp.Body)
		serveError(w, fmt.Errorf("Error"))
		return
	}
	defer resp.Body.Close()
	b, _ := ioutil.ReadAll(resp.Body)
	var sc StripeCustomer
	if err := json.Unmarshal(b, &sc); err != nil {
		serveError(w, err)
		return
	}
	if err := gn.RunInTransaction(func(gn *goon.Goon) error {
		if err := gn.Get(&u); err != nil && err != datastore.ErrNoSuchEntity {
			return err
		}
		if err := gn.Get(&uc); err != nil && err != datastore.ErrNoSuchEntity {
			return err
		}
		u.Account = APaid
		uc.Customer = sc.Id
		uc.Last4 = sc.Card.Last4
		uc.Created = time.Unix(sc.Created, 0)
		_, err := gn.PutMany(&u, &uc)
		return err
	}, nil); err != nil {
		serveError(w, err)
		return
	}
	b, _ = json.Marshal(&uc)
	w.Write(b)
}

func Account(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	u := User{Id: cu.ID}
	uc := UserCharge{Id: 1, Parent: gn.Key(&u)}
	if err := gn.Get(&uc); err == nil {
		b, _ := json.Marshal(&uc)
		w.Write(b)
	} else if err != datastore.ErrNoSuchEntity {
		serveError(w, err)
		return
	}
}

func Uncheckout(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	u := User{Id: cu.ID}
	uc := UserCharge{Id: 1, Parent: gn.Key(&u)}
	if err := gn.Get(&u); err != nil {
		serveError(w, err)
		return
	}
	if err := gn.Get(&uc); err != nil || len(uc.Customer) == 0 {
		serveError(w, err)
		return
	}
	resp, err := stripe(c, "DELETE", "customers/"+uc.Customer, "")
	if err != nil {
		serveError(w, err)
		return
	} else if resp.StatusCode != http.StatusOK {
		serveError(w, fmt.Errorf("Error"))
		return
	}
	if err := gn.RunInTransaction(func(gn *goon.Goon) error {
		if err := gn.Get(&u); err != nil && err != datastore.ErrNoSuchEntity {
			return err
		}
		u.Account = AFree
		if err := gn.Delete(gn.Key(&uc)); err != nil {
			return err
		}
		_, err := gn.Put(&u)
		return err
	}, nil); err != nil {
		serveError(w, err)
		return
	}
	b, _ := json.Marshal(&uc)
	w.Write(b)
}

func stripe(c mpg.Context, method, urlStr, body string) (*http.Response, error) {
	cl := &http.Client{
		Transport: &urlfetch.Transport{
			Context:  c,
			Deadline: time.Minute,
		},
	}
	req, err := http.NewRequest(method, fmt.Sprintf("https://api.stripe.com/v1/%s", urlStr), strings.NewReader(body))
	if err != nil {
		return nil, err
	}
	req.SetBasicAuth(STRIPE_SECRET, "")
	return cl.Do(req)
}

func Donate(c mpg.Context, w http.ResponseWriter, r *http.Request) {
	cu := user.Current(c)
	gn := goon.FromContext(c)
	u := User{Id: cu.ID}
	if err := gn.Get(&u); err != nil {
		serveError(w, err)
		return
	}
	amount, err := strconv.Atoi(r.FormValue("amount"))
	if err != nil || amount < 200 {
		serveError(w, fmt.Errorf("bad amount: %v", r.FormValue("amount")))
		return
	}
	resp, err := stripe(c, "POST", "charges", url.Values{
		"amount":      {r.FormValue("amount")},
		"description": {fmt.Sprintf("%v - %v", u.Id, u.Email)},
		"card":        {r.FormValue("stripeToken")},
		"currency":    {"usd"},
	}.Encode())
	if err != nil {
		serveError(w, err)
		return
	} else if resp.StatusCode != http.StatusOK {
		c.Errorf("%s", resp.Body)
		serveError(w, fmt.Errorf("Error"))
		return
	}
}
<|endoftext|>


<commit_before>package main

import (
	"context"
	"fmt"
	"time"

	pb "github.com/brotherlogic/gobuildslave/proto"
	"github.com/brotherlogic/goserver/utils"

	dpb "github.com/brotherlogic/discovery/proto"
	pbgs "github.com/brotherlogic/goserver/proto"
)

func (s *Server) trackUpTime(ctx context.Context) error {
	conn, err := s.DialMaster("discover")
	if err != nil {
		return err
	}
	defer conn.Close()

	client := pbgs.NewGoserverServiceClient(conn)
	state, err := client.State(ctx, &pbgs.Empty{})

	if err != nil {
		return err
	}

	for _, st := range state.GetStates() {
		if st.Key == "startup_time" {
			s.discoverStartup = time.Unix(st.TimeValue, 0)
			return nil
		}
	}

	return fmt.Errorf("No change made: %v -> %v", err, state)
}

func (s *Server) runOnChange() error {
	ctx, cancel := utils.ManualContext("gbsrr", "gbsrr", time.Minute, false)
	defer cancel()

	var jj *pb.JobAssignment
	if len(s.njobs) > 0 {
		for _, val := range s.njobs {
			jj = val
		}
	}
	s.Log(fmt.Sprintf("Resyncing on %v jobs (First is %v)", len(s.njobs), jj))
	_, err := s.Reregister(ctx, &pbgs.ReregisterRequest{})
	if err != nil {
		return err
	}
	for _, job := range s.njobs {
		if job.Port > 0 {
			conn, err := s.FDial(fmt.Sprintf("%v:%v", s.Registry.Ip, job.Port))
			if err != nil {
				s.Log(fmt.Sprintf("Cannot dial %v,%v -> %v", s.Registry.Ip, job.Port, err))
				break
			}
			defer conn.Close()
			client := pbgs.NewGoserverServiceClient(conn)
			_, err = client.Reregister(ctx, &pbgs.ReregisterRequest{})
			if err != nil {
				s.Log(fmt.Sprintf("Reregister failed: %v", err))
			}
		}
	}

	return nil
}

func (s *Server) unregisterChildren() error {
	ctx, cancel := utils.BuildContext("gobuildslave-unreg", "gobuildslave")
	defer cancel()

	conn, err := s.DoDial(&dpb.RegistryEntry{Ip: utils.RegistryIP, Port: utils.RegistryPort})
	if err != nil {
		return err
	}
	defer conn.Close()

	client := dpb.NewDiscoveryServiceV2Client(conn)
	_, err = client.Unregister(ctx, &dpb.UnregisterRequest{Service: &dpb.RegistryEntry{Identifier: s.Registry.Identifier}})

	return err
}
<commit_msg>Added an extra logging step<commit_after>package main

import (
	"context"
	"fmt"
	"time"

	pb "github.com/brotherlogic/gobuildslave/proto"
	"github.com/brotherlogic/goserver/utils"

	dpb "github.com/brotherlogic/discovery/proto"
	pbgs "github.com/brotherlogic/goserver/proto"
)

func (s *Server) trackUpTime(ctx context.Context) error {
	conn, err := s.DialMaster("discover")
	if err != nil {
		return err
	}
	defer conn.Close()

	client := pbgs.NewGoserverServiceClient(conn)
	state, err := client.State(ctx, &pbgs.Empty{})

	if err != nil {
		return err
	}

	for _, st := range state.GetStates() {
		if st.Key == "startup_time" {
			s.discoverStartup = time.Unix(st.TimeValue, 0)
			return nil
		}
	}

	return fmt.Errorf("No change made: %v -> %v", err, state)
}

func (s *Server) runOnChange() error {
	ctx, cancel := utils.ManualContext("gbsrr", "gbsrr", time.Minute, false)
	defer cancel()

	var jj *pb.JobAssignment
	if len(s.njobs) > 0 {
		for _, val := range s.njobs {
			jj = val
		}
	}
	s.Log(fmt.Sprintf("Resyncing on %v jobs (First is %v)", len(s.njobs), jj))
	_, err := s.Reregister(ctx, &pbgs.ReregisterRequest{})
	if err != nil {
		return err
	}
	for _, job := range s.njobs {
		if job.Port > 0 {
			conn, err := s.FDial(fmt.Sprintf("%v:%v", s.Registry.Ip, job.Port))
			if err != nil {
				s.Log(fmt.Sprintf("Cannot dial %v,%v -> %v", s.Registry.Ip, job.Port, err))
				break
			}
			defer conn.Close()
			client := pbgs.NewGoserverServiceClient(conn)
			_, err = client.Reregister(ctx, &pbgs.ReregisterRequest{})
			if err != nil {
				s.Log(fmt.Sprintf("Reregister failed: %v", err))
			}
		} else {
			time.Sleep(time.Second)
			s.Log(fmt.Sprintf("Job %v has no port", job))
		}
	}

	return nil
}

func (s *Server) unregisterChildren() error {
	ctx, cancel := utils.BuildContext("gobuildslave-unreg", "gobuildslave")
	defer cancel()

	conn, err := s.DoDial(&dpb.RegistryEntry{Ip: utils.RegistryIP, Port: utils.RegistryPort})
	if err != nil {
		return err
	}
	defer conn.Close()

	client := dpb.NewDiscoveryServiceV2Client(conn)
	_, err = client.Unregister(ctx, &dpb.UnregisterRequest{Service: &dpb.RegistryEntry{Identifier: s.Registry.Identifier}})

	return err
}
<|endoftext|>


<commit_before>/*

build is a package that can create and cleanup api server binaries, static
asset folders, and golden test setups.

Typically it is not used directly, but via the `boardgame-util build` and
`boardgame-util cleanup` commands.

*/
package build

import (
	"errors"
	"os"
	"strings"
)

type StorageType int

const (
	StorageInvalid StorageType = iota
	StorageMemory
	StorageBolt
	StorageMysql
	StorageFilesystem
)

func StorageTypeFromString(in string) StorageType {
	in = strings.ToLower(in)
	in = strings.TrimSpace(in)

	switch in {
	case "memory":
		return StorageMemory
	case "bolt":
		return StorageBolt
	case "mysql":
		return StorageMysql
	case "filesystem":
		return StorageFilesystem
	}

	return StorageInvalid
}

/*

Api generates the code for a server with the following imported games and
given storage type, builds it, and returns the path to the compiled binary.

To clean up the binary, call CleanupApi and pass the same directory.

*/
func Api(directory string, managers []string, storage StorageType) (string, error) {
	return "", errors.New("Not yet implemented")
}

func CleanupApi(directory string) error {
	return os.RemoveAll(directory)
}
<commit_msg>Add a few more methods to StorageType. Part of #655.<commit_after>/*

build is a package that can create and cleanup api server binaries, static
asset folders, and golden test setups.

Typically it is not used directly, but via the `boardgame-util build` and
`boardgame-util cleanup` commands.

*/
package build

import (
	"errors"
	"os"
	"path/filepath"
	"strings"
)

type StorageType int

const (
	StorageInvalid StorageType = iota
	StorageMemory
	StorageBolt
	StorageMysql
	StorageFilesystem
)

func StorageTypeFromString(in string) StorageType {
	in = strings.ToLower(in)
	in = strings.TrimSpace(in)

	switch in {
	case "memory":
		return StorageMemory
	case "bolt":
		return StorageBolt
	case "mysql":
		return StorageMysql
	case "filesystem":
		return StorageFilesystem
	}

	return StorageInvalid
}

func (s StorageType) String() string {
	switch s {
	case StorageMemory:
		return "memory"
	case StorageBolt:
		return "bolt"
	case StorageMysql:
		return "mysql"
	case StorageFilesystem:
		return "filesystem"
	}
	return "invalid"
}

//Import is the string denting the import path for this storage type.
func (s StorageType) Import() string {
	base := "github.com/jkomoros/boardgame/storage"
	return filepath.Join(base, s.String())
}

//Constructor is a string representing a default constructor for this storage
//type, e.g. `bolt.NewStorageManager(".database")`
func (s StorageType) Constructor() string {

	args := ""

	switch s {
	case StorageFilesystem:
		args = "games/"
	case StorageBolt:
		args = ".database"
	}

	return s.String() + "(" + args + ")"

}

/*

Api generates the code for a server with the following imported games and
given storage type, builds it, and returns the path to the compiled binary.

To clean up the binary, call CleanupApi and pass the same directory.

*/
func Api(directory string, managers []string, storage StorageType) (string, error) {
	return "", errors.New("Not yet implemented")
}

func CleanupApi(directory string) error {
	return os.RemoveAll(directory)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"testing"

	. "github.com/VonC/godbg"
	. "github.com/smartystreets/goconvey/convey"
)

func TestGoPanic(t *testing.T) {
	Convey("Test main", t, func() {
		fmt.Println("test main")
		files, err := ioutil.ReadDir("./tests")
		if err != nil {
			Pdbgf("Unable to access tests folder\n'%v'\n", err)
			t.Fail()
		}
		for _, file := range files {
			Pdbgf(file.Name())
			if in, err = os.Open("tests/" + file.Name()); err == nil {
				Pdbgf("ok open")
				main()
			} else {
				Pdbgf("Unable to access open file '%v'\n'%v'\n", file.Name(), err)
				t.Fail()
			}
		}
	})
}
<commit_msg>Introduce focusing on specific test file<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"testing"

	. "github.com/VonC/godbg"
	. "github.com/smartystreets/goconvey/convey"
)

func TestGoPanic(t *testing.T) {
	Convey("Test main", t, func() {
		fmt.Println("test main")
		files, err := ioutil.ReadDir("./tests")
		if err != nil {
			Pdbgf("Unable to access tests folder\n'%v'\n", err)
			t.Fail()
		}
		for _, file := range files {
			if file.Name() != "exceptionstack2" {
				continue
			}
			Pdbgf(file.Name())
			if in, err = os.Open("tests/" + file.Name()); err == nil {
				Pdbgf("ok open")
				main()
			} else {
				Pdbgf("Unable to access open file '%v'\n'%v'\n", file.Name(), err)
				t.Fail()
			}
		}
	})
}
<|endoftext|>


<commit_before>package d2s

import (
	"encoding/json"
	"fmt"
	"time"
)

// Character represents all the d2s character data.
type Character struct {
	Header      header     `json:"header"`
	Attributes  attributes `json:"attributes"`
	Skills      []skill    `json:"skills"`
	Items       []item     `json:"items"`
	CorpseItems []item     `json:"corpse_items"`
	MercItems   []item     `json:"merc_items"`
	GolemItem   *item      `json:"golem_item"`
	IsDead      uint16     `json:"is_dead"`
}

func (h *header) MarshalJSON() ([]byte, error) {
	type Alias header

	leftSkill, ok := skillMap[int(h.LeftSkill)]
	if !ok {
		leftSkill = ""
	}

	rightSkill, ok := skillMap[int(h.RightSkill)]
	if !ok {
		rightSkill = ""
	}

	leftSwapSkill, ok := skillMap[int(h.LeftSwapSkill)]
	if !ok {
		leftSwapSkill = ""
	}

	rightSwapSkill, ok := skillMap[int(h.RightSwapSkill)]
	if !ok {
		rightSwapSkill = ""
	}

	var assignedSkills []string
	for _, skillID := range h.AssignedSkills {
		skill, ok := skillMap[int(skillID)]
		if ok {
			assignedSkills = append(assignedSkills, skill)
		}
	}

	return json.Marshal(&struct {
		Identifier     string         `json:"identifier"`
		CheckSum       string         `json:"checksum"`
		Name           string         `json:"name"`
		Status         readableStatus `json:"status"`
		Class          string         `json:"class"`
		LastPlayed     string         `json:"last_played"`
		LeftSkill      string         `json:"left_skill"`
		RightSkill     string         `json:"right_skill"`
		LeftSwapSkill  string         `json:"left_swap_skill"`
		RightSwapSkill string         `json:"right_swap_skill"`
		MercID         string         `json:"merc_id"`
		AssignedSkills []string       `json:"assigned_skills"`
		QuestsNormal   quests         `json:"quests_normal"`
		QuestsNm       quests         `json:"quests_nm"`
		QuestsHell     quests         `json:"quests_hell"`
		*Alias
	}{
		Identifier:     fmt.Sprintf("%x", h.Identifier),
		CheckSum:       fmt.Sprintf("%x", h.CheckSum),
		Name:           h.Name.String(),
		Status:         h.Status.Readable(),
		Class:          h.Class.String(),
		LastPlayed:     time.Unix(int64(h.LastPlayed), 0).String(),
		LeftSkill:      leftSkill,
		RightSkill:     rightSkill,
		LeftSwapSkill:  leftSwapSkill,
		RightSwapSkill: rightSwapSkill,
		MercID:         fmt.Sprintf("%x", h.MercID),
		AssignedSkills: assignedSkills,
		QuestsNormal:   h.QuestsNormal,
		QuestsNm:       h.QuestsNm,
		QuestsHell:     h.QuestsHell,
		Alias:          (*Alias)(h),
	})
}

// Header determines the header data of a d2s file.
type header struct {
	Identifier        uint32      `json:"identifier"`
	Version           uint32      `json:"version"`
	FileSize          uint32      `json:"filesize"`
	CheckSum          uint32      `json:"checksum"`
	ActiveArms        uint32      `json:"active_arms"`
	Name              name        `json:"name"`
	Status            status      `json:"status"`
	Progression       progression `json:"progression"`
	_                 [2]byte
	Class             class `json:"class"`
	_                 [2]byte
	Level             byte `json:"level"`
	_                 [4]byte
	LastPlayed        uint32 `json:"last_played"`
	_                 [4]byte
	AssignedSkills    [16]uint32 `json:"assigned_skills"`
	LeftSkill         uint32     `json:"left_skill"`
	RightSkill        uint32     `json:"right_skill"`
	LeftSwapSkill     uint32     `json:"left_swap_skill"`
	RightSwapSkill    uint32     `json:"right_swap_skill"`
	_                 [32]byte
	CurrentDifficulty difficulty `json:"difficulty"`
	MapID             uint32     `json:"map_id"`
	_                 [2]byte
	DeadMerc          uint16 `json:"dead_merc"`
	MercID            uint32 `json:"merc_id"`
	MercNameID        uint16 `json:"merc_name_id"`
	MercType          uint16 `json:"merc_type"`
	MercExp           uint32 `json:"merc_experience"`
	_                 [144]byte
	QuestHeader       [4]byte `json:"-"`
	_                 [6]byte
	QuestsNormal      quests  `json:"quests_normal"`
	QuestsNm          quests  `json:"quests_nm"`
	QuestsHell        quests  `json:"quests_hell"`
	WaypointHeader    [2]byte `json:"-"`
	_                 [6]byte
	WaypointsNormal   [24]byte `json:"-"`
	WaypointsNm       [24]byte `json:"-"`
	WaypointsHell     [24]byte `json:"-"`
	WaypointTrailer   byte     `json:"-"`
	NPCHeader         [2]byte  `json:"-"`
	_                 byte
	NPCIntroNormal    [5]byte `json:"-"`
	_                 [3]byte
	NPCIntroNm        [5]byte `json:"-"`
	_                 [3]byte
	NPCIntroHell      [5]byte `json:"-"`
	_                 [3]byte
	NPCReturnNorm     [4]byte `json:"-"`
	_                 [4]byte
	NPCReturnNm       [4]byte `json:"-"`
	_                 [4]byte
	NPCReturnHell     [4]byte `json:"-"`
	_                 [4]byte
	StatHeader        [2]byte `json:"-"`
}

type skillData struct {
	Header [2]byte
	List   [30]byte
}

type itemData struct {
	Header [2]byte
	Count  uint16
}

type corpseData struct {
	Header  [2]byte
	Count   uint16
	Unknown [12]byte
}

type golemData struct {
	Header   [2]byte
	HasGolem byte
}
<commit_msg>Updated last played to unix time.<commit_after>package d2s

import (
	"encoding/json"
	"fmt"
)

// Character represents all the d2s character data.
type Character struct {
	Header      header     `json:"header"`
	Attributes  attributes `json:"attributes"`
	Skills      []skill    `json:"skills"`
	Items       []item     `json:"items"`
	CorpseItems []item     `json:"corpse_items"`
	MercItems   []item     `json:"merc_items"`
	GolemItem   *item      `json:"golem_item"`
	IsDead      uint16     `json:"is_dead"`
}

func (h *header) MarshalJSON() ([]byte, error) {
	type Alias header

	leftSkill, ok := skillMap[int(h.LeftSkill)]
	if !ok {
		leftSkill = ""
	}

	rightSkill, ok := skillMap[int(h.RightSkill)]
	if !ok {
		rightSkill = ""
	}

	leftSwapSkill, ok := skillMap[int(h.LeftSwapSkill)]
	if !ok {
		leftSwapSkill = ""
	}

	rightSwapSkill, ok := skillMap[int(h.RightSwapSkill)]
	if !ok {
		rightSwapSkill = ""
	}

	var assignedSkills []string
	for _, skillID := range h.AssignedSkills {
		skill, ok := skillMap[int(skillID)]
		if ok {
			assignedSkills = append(assignedSkills, skill)
		}
	}

	return json.Marshal(&struct {
		Identifier     string         `json:"identifier"`
		CheckSum       string         `json:"checksum"`
		Name           string         `json:"name"`
		Status         readableStatus `json:"status"`
		Class          string         `json:"class"`
		LastPlayed     uint32         `json:"last_played"`
		LeftSkill      string         `json:"left_skill"`
		RightSkill     string         `json:"right_skill"`
		LeftSwapSkill  string         `json:"left_swap_skill"`
		RightSwapSkill string         `json:"right_swap_skill"`
		MercID         string         `json:"merc_id"`
		AssignedSkills []string       `json:"assigned_skills"`
		QuestsNormal   quests         `json:"quests_normal"`
		QuestsNm       quests         `json:"quests_nm"`
		QuestsHell     quests         `json:"quests_hell"`
		*Alias
	}{
		Identifier:     fmt.Sprintf("%x", h.Identifier),
		CheckSum:       fmt.Sprintf("%x", h.CheckSum),
		Name:           h.Name.String(),
		Status:         h.Status.Readable(),
		Class:          h.Class.String(),
		LastPlayed:     h.LastPlayed * 1000,
		LeftSkill:      leftSkill,
		RightSkill:     rightSkill,
		LeftSwapSkill:  leftSwapSkill,
		RightSwapSkill: rightSwapSkill,
		MercID:         fmt.Sprintf("%x", h.MercID),
		AssignedSkills: assignedSkills,
		QuestsNormal:   h.QuestsNormal,
		QuestsNm:       h.QuestsNm,
		QuestsHell:     h.QuestsHell,
		Alias:          (*Alias)(h),
	})
}

// Header determines the header data of a d2s file.
type header struct {
	Identifier        uint32      `json:"identifier"`
	Version           uint32      `json:"version"`
	FileSize          uint32      `json:"filesize"`
	CheckSum          uint32      `json:"checksum"`
	ActiveArms        uint32      `json:"active_arms"`
	Name              name        `json:"name"`
	Status            status      `json:"status"`
	Progression       progression `json:"progression"`
	_                 [2]byte
	Class             class `json:"class"`
	_                 [2]byte
	Level             byte `json:"level"`
	_                 [4]byte
	LastPlayed        uint32 `json:"last_played"`
	_                 [4]byte
	AssignedSkills    [16]uint32 `json:"assigned_skills"`
	LeftSkill         uint32     `json:"left_skill"`
	RightSkill        uint32     `json:"right_skill"`
	LeftSwapSkill     uint32     `json:"left_swap_skill"`
	RightSwapSkill    uint32     `json:"right_swap_skill"`
	_                 [32]byte
	CurrentDifficulty difficulty `json:"difficulty"`
	MapID             uint32     `json:"map_id"`
	_                 [2]byte
	DeadMerc          uint16 `json:"dead_merc"`
	MercID            uint32 `json:"merc_id"`
	MercNameID        uint16 `json:"merc_name_id"`
	MercType          uint16 `json:"merc_type"`
	MercExp           uint32 `json:"merc_experience"`
	_                 [144]byte
	QuestHeader       [4]byte `json:"-"`
	_                 [6]byte
	QuestsNormal      quests  `json:"quests_normal"`
	QuestsNm          quests  `json:"quests_nm"`
	QuestsHell        quests  `json:"quests_hell"`
	WaypointHeader    [2]byte `json:"-"`
	_                 [6]byte
	WaypointsNormal   [24]byte `json:"-"`
	WaypointsNm       [24]byte `json:"-"`
	WaypointsHell     [24]byte `json:"-"`
	WaypointTrailer   byte     `json:"-"`
	NPCHeader         [2]byte  `json:"-"`
	_                 byte
	NPCIntroNormal    [5]byte `json:"-"`
	_                 [3]byte
	NPCIntroNm        [5]byte `json:"-"`
	_                 [3]byte
	NPCIntroHell      [5]byte `json:"-"`
	_                 [3]byte
	NPCReturnNorm     [4]byte `json:"-"`
	_                 [4]byte
	NPCReturnNm       [4]byte `json:"-"`
	_                 [4]byte
	NPCReturnHell     [4]byte `json:"-"`
	_                 [4]byte
	StatHeader        [2]byte `json:"-"`
}

type skillData struct {
	Header [2]byte
	List   [30]byte
}

type itemData struct {
	Header [2]byte
	Count  uint16
}

type corpseData struct {
	Header  [2]byte
	Count   uint16
	Unknown [12]byte
}

type golemData struct {
	Header   [2]byte
	HasGolem byte
}
<|endoftext|>


<commit_before>package main

import "fmt"
import "time"
import "runtime"
import "github.com/veandco/go-sdl2/sdl"
import "github.com/veandco/go-sdl2/sdl_image"
import "github.com/ungerik/go3d/vec2"

const width = 800
const height = 600

func rect32(x int, y int, w int, h int) sdl.Rect {
	return sdl.Rect{int32(x), int32(y), int32(w), int32(h)}
}

func point32(x int, y int) sdl.Point {
	return sdl.Point{int32(x), int32(y)}
}

type Vehicle struct {
	pos vec2.T
	vel vec2.T
	acc vec2.T
	box sdl.Rect // for drawing
}

func (v *Vehicle) updateBox() {
	v.box.X = int32(v.pos[0])
	v.box.Y = int32(v.pos[1])
}

func (v *Vehicle) bound(width int, height int) {
	w := float32(width) - float32(v.box.W)
	h := float32(height) - float32(v.box.H)

	if v.pos[0] < 0 {
		v.pos[0] = 0
		v.vel[0] = -1 * v.vel[0]
	}
	if v.pos[0] > w  {
		v.pos[0] = w
		v.vel[0] = -1 * v.vel[0]
	}
	if v.pos[1] < 0 {
		v.pos[1] = 0
		v.vel[1] = -1 * v.vel[1]
	}
	if v.pos[1] > h {
		v.pos[1] = h
		v.vel[1] = -1 * v.vel[1]
	}
}

func main() {
	fmt.Println("Started...")
	runtime.LockOSThread()

	window, renderer := initSDL()
	defer window.Destroy()
	defer renderer.Destroy()

	// example draw green square
	//	renderer.SetDrawColor(0x00, 0xFF, 0x00, 0xFF)
	//	renderer.DrawRect(&sdl.Rect{0,0,100,100})

	shipTexture, _ := img.LoadTexture(renderer, "plane.png")
	defer shipTexture.Destroy()

	// correct size
	_, _, shipW, shipH, _ := shipTexture.Query()
	sdlBox := rect32(0, 0, shipW, shipH)

	// center it
	x1 := (width - shipW) / 2
	y1 := (height - shipH) / 2
	pos := vec2.T{float32(x1), float32(y1)}

	ship := Vehicle{pos, vec2.Zero, vec2.Zero, sdlBox}

	// clear with black
	renderer.SetDrawColor(0, 0, 0, 0xFF)

	//
	//forces := [2]vec2.T{vec2}
	gravity := vec2.T{0, 10}
	wind := vec2.T{1, 0}
	speed := 10

	ticker := time.NewTicker(time.Millisecond * 16)
	keepRunning := true
	ticks := sdl.GetTicks()

	for keepRunning {
		for {
			e := sdl.PollEvent()
			if e == nil {
				break
			}
			switch e.(type) {
			case *sdl.QuitEvent:
				ticker.Stop()
				keepRunning = false
			}

		}

		now := sdl.GetTicks()
		timePassed := now - ticks
		delta := float32(timePassed) * .0001 * float32(speed)
		ticks = now

		gr := gravity.Scaled(delta)
		wd := wind.Scaled(delta)
		ship.acc.Add(&gr)
		ship.acc.Add(&wd)
		ship.vel.Add(&ship.acc)
		ship.pos.Add(&ship.vel)
		ship.acc.Mul(&vec2.Zero)

		ship.bound(width, height)

		ship.updateBox()

		renderer.Clear()
		_ = renderer.CopyEx(shipTexture, nil, &ship.box, 35, nil, sdl.FLIP_NONE)
		renderer.Present()
		<-ticker.C
		//fmt.Println("ticker ticked")
	}

}

func initSDL() (*sdl.Window, *sdl.Renderer) {
	// Initialize
	err := sdl.Init(sdl.INIT_VIDEO)
	if err != nil {
		panic(err)
	}

	// Setup Window
	window, err := sdl.CreateWindow("Here's a Screen", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		width, height, sdl.WINDOW_SHOWN)
	if err != nil {
		panic(err)
	}

	// Renderer
	renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED|sdl.RENDERER_PRESENTVSYNC)
	if renderer == nil {
		panic(err)
	}

	return window, renderer
}
<commit_msg>add heading angle<commit_after>package main

import "fmt"
import "time"
import "runtime"
import "github.com/veandco/go-sdl2/sdl"
import "github.com/veandco/go-sdl2/sdl_image"
import "github.com/ungerik/go3d/vec2"

const width = 800
const height = 600

func rect32(x int, y int, w int, h int) sdl.Rect {
	return sdl.Rect{int32(x), int32(y), int32(w), int32(h)}
}

func point32(x int, y int) sdl.Point {
	return sdl.Point{int32(x), int32(y)}
}

type Vehicle struct {
	pos vec2.T
	vel vec2.T
	acc vec2.T
	box sdl.Rect // for drawing
}

func (v *Vehicle) updateBox() {
	v.box.X = int32(v.pos[0])
	v.box.Y = int32(v.pos[1])
}

func (v *Vehicle) bound(width int, height int) {
	w := float32(width) - float32(v.box.W)
	h := float32(height) - float32(v.box.H)

	if v.pos[0] < 0 {
		v.pos[0] = 0
		v.vel[0] = -1 * v.vel[0]
	}
	if v.pos[0] > w  {
		v.pos[0] = w
		v.vel[0] = -1 * v.vel[0]
	}
	if v.pos[1] < 0 {
		v.pos[1] = 0
		v.vel[1] = -1 * v.vel[1]
	}
	if v.pos[1] > h {
		v.pos[1] = h
		v.vel[1] = -1 * v.vel[1]
	}
}

func main() {
	fmt.Println("Started...")
	runtime.LockOSThread()

	window, renderer := initSDL()
	defer window.Destroy()
	defer renderer.Destroy()

	// example draw green square
	//	renderer.SetDrawColor(0x00, 0xFF, 0x00, 0xFF)
	//	renderer.DrawRect(&sdl.Rect{0,0,100,100})

	shipTexture, _ := img.LoadTexture(renderer, "plane.png")
	defer shipTexture.Destroy()

	// correct size
	_, _, shipW, shipH, _ := shipTexture.Query()
	sdlBox := rect32(0, 0, shipW, shipH)

	// center it
	x1 := (width - shipW) / 2
	y1 := (height - shipH) / 2
	pos := vec2.T{float32(x1), float32(y1)}

	ship := Vehicle{pos, vec2.Zero, vec2.Zero, sdlBox}

	// clear with black
	renderer.SetDrawColor(0, 0, 0, 0xFF)

	//
	//forces := [2]vec2.T{vec2}
	gravity := vec2.T{0, 10}
	wind := vec2.T{1, 0}
	speed := 10

	ticker := time.NewTicker(time.Millisecond * 16)
	keepRunning := true
	ticks := sdl.GetTicks()

	for keepRunning {
		for {
			e := sdl.PollEvent()
			if e == nil {
				break
			}
			switch e.(type) {
			case *sdl.QuitEvent:
				ticker.Stop()
				keepRunning = false
			}

		}

		now := sdl.GetTicks()
		timePassed := now - ticks
		delta := float32(timePassed) * .0001 * float32(speed)
		ticks = now

		gr := gravity.Scaled(delta)
		wd := wind.Scaled(delta)
		ship.acc.Add(&gr)
		ship.acc.Add(&wd)
		ship.vel.Add(&ship.acc)
		ship.pos.Add(&ship.vel)
		ship.acc.Mul(&vec2.Zero)

		ship.bound(width, height)

		ship.updateBox()

		renderer.Clear()
		angle := 90 + ship.vel.Angle() * 57.29
		_ = renderer.CopyEx(shipTexture, nil, &ship.box, float64(angle), nil, sdl.FLIP_NONE)
		renderer.Present()
		<-ticker.C
		//fmt.Println("ticker ticked")
	}

}

func initSDL() (*sdl.Window, *sdl.Renderer) {
	// Initialize
	err := sdl.Init(sdl.INIT_VIDEO)
	if err != nil {
		panic(err)
	}

	// Setup Window
	window, err := sdl.CreateWindow("Here's a Screen", sdl.WINDOWPOS_UNDEFINED, sdl.WINDOWPOS_UNDEFINED,
		width, height, sdl.WINDOW_SHOWN)
	if err != nil {
		panic(err)
	}

	// Renderer
	renderer, err := sdl.CreateRenderer(window, -1, sdl.RENDERER_ACCELERATED|sdl.RENDERER_PRESENTVSYNC)
	if renderer == nil {
		panic(err)
	}

	return window, renderer
}
<|endoftext|>


<commit_before>// Copyright 2011 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.

// +build !appengine

package main

import (
	"flag"
	"fmt"
	"go/build"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"code.google.com/p/go.talks/pkg/socket"

	// Imports so that go build/install automatically installs them.
	_ "code.google.com/p/go-tour/pic"
	_ "code.google.com/p/go-tour/tree"
	_ "code.google.com/p/go-tour/wc"
)

const (
	basePkg    = "code.google.com/p/go-tour/"
	socketPath = "/socket"
)

var (
	httpListen  = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput  = flag.Bool("html", false, "render program output as HTML")
	openBrowser = flag.Bool("openbrowser", true, "open browser automatically")
)

var (
	// a source of numbers, for naming temporary files
	uniq = make(chan int)

	// GOPATH containing the tour packages
	gopath = os.Getenv("GOPATH")

	httpAddr string
)

func isRoot(path string) bool {
	_, err := os.Stat(filepath.Join(path, "tour.article"))
	return err == nil
}

func findRoot() (string, error) {
	ctx := build.Default
	p, err := ctx.Import(basePkg, "", build.FindOnly)
	if err == nil && isRoot(p.Dir) {
		return p.Dir, nil
	}
	tourRoot := filepath.Join(runtime.GOROOT(), "misc", "tour")
	ctx.GOPATH = tourRoot
	p, err = ctx.Import(basePkg, "", build.FindOnly)
	if err == nil && isRoot(tourRoot) {
		gopath = tourRoot
		return tourRoot, nil
	}
	return "", fmt.Errorf("could not find go-tour content; check $GOROOT and $GOPATH")
}

func main() {
	flag.Parse()

	// source of unique numbers
	go func() {
		for i := 0; ; i++ {
			uniq <- i
		}
	}()

	// find and serve the go tour files
	root, err := findRoot()
	if err != nil {
		log.Fatalf("Couldn't find tour files: %v", err)
	}

	log.Println("Serving content from", root)

	host, port, err := net.SplitHostPort(*httpListen)
	if err != nil {
		log.Fatal(err)
	}
	if host == "" {
		host = "localhost"
	}
	if host != "127.0.0.1" && host != "localhost" {
		log.Print(localhostWarning)
	}
	httpAddr = host + ":" + port

	if err := initTour(root); err != nil {
		log.Fatal(err)
	}

	fs := http.FileServer(http.Dir(root))
	http.Handle("/favicon.ico", fs)
	http.Handle("/static/", fs)
	http.Handle("/talks/", fs)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" {
			if err := renderTour(w); err != nil {
				log.Println(err)
			}
			return
		}
		http.Error(w, "not found", 404)
	})

	http.Handle(socketPath, socket.Handler)

	err = serveScripts(filepath.Join(root, "js"), "SocketTransport")
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		url := "http://" + httpAddr
		if waitServer(url) && *openBrowser && startBrowser(url) {
			log.Printf("A browser window should open. If not, please visit %s", url)
		} else {
			log.Printf("Please open your web browser and visit %s", url)
		}
	}()
	log.Fatal(http.ListenAndServe(httpAddr, nil))
}

const localhostWarning = `
WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`

type response struct {
	Output string `json:"output"`
	Errors string `json:"compile_errors"`
}

func init() {
	socket.Environ = environ
}

// environ returns the original execution environment with GOPATH
// replaced (or added) with the value of the global var gopath.
func environ() (env []string) {
	for _, v := range os.Environ() {
		if !strings.HasPrefix(v, "GOPATH=") {
			env = append(env, v)
		}
	}
	env = append(env, "GOPATH="+gopath)
	return
}

// waitServer waits some time for the http Server to start
// serving url and returns whether it starts
func waitServer(url string) bool {
	tries := 20
	for tries > 0 {
		resp, err := http.Get(url)
		if err == nil {
			resp.Body.Close()
			return true
		}
		time.Sleep(100 * time.Millisecond)
		tries--
	}
	return false
}

// startBrowser tries to open the URL in a browser, and returns
// whether it succeed.
func startBrowser(url string) bool {
	// try to start the browser
	var args []string
	switch runtime.GOOS {
	case "darwin":
		args = []string{"open"}
	case "windows":
		args = []string{"cmd", "/c", "start"}
	default:
		args = []string{"xdg-open"}
	}
	cmd := exec.Command(args[0], append(args[1:], url)...)
	return cmd.Start() == nil
}

// prepContent for the local tour simply returns the content as-is.
func prepContent(r io.Reader) io.Reader { return r }

// socketAddr returns the WebSocket handler address.
func socketAddr() string { return "ws://" + httpAddr + socketPath }
<commit_msg>go-tour: remove unnecessary code<commit_after>// Copyright 2011 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.

// +build !appengine

package main

import (
	"flag"
	"fmt"
	"go/build"
	"io"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"time"

	"code.google.com/p/go.talks/pkg/socket"

	// Imports so that go build/install automatically installs them.
	_ "code.google.com/p/go-tour/pic"
	_ "code.google.com/p/go-tour/tree"
	_ "code.google.com/p/go-tour/wc"
)

const (
	basePkg    = "code.google.com/p/go-tour/"
	socketPath = "/socket"
)

var (
	httpListen  = flag.String("http", "127.0.0.1:3999", "host:port to listen on")
	htmlOutput  = flag.Bool("html", false, "render program output as HTML")
	openBrowser = flag.Bool("openbrowser", true, "open browser automatically")
)

var (
	// GOPATH containing the tour packages
	gopath = os.Getenv("GOPATH")

	httpAddr string
)

func isRoot(path string) bool {
	_, err := os.Stat(filepath.Join(path, "tour.article"))
	return err == nil
}

func findRoot() (string, error) {
	ctx := build.Default
	p, err := ctx.Import(basePkg, "", build.FindOnly)
	if err == nil && isRoot(p.Dir) {
		return p.Dir, nil
	}
	tourRoot := filepath.Join(runtime.GOROOT(), "misc", "tour")
	ctx.GOPATH = tourRoot
	p, err = ctx.Import(basePkg, "", build.FindOnly)
	if err == nil && isRoot(tourRoot) {
		gopath = tourRoot
		return tourRoot, nil
	}
	return "", fmt.Errorf("could not find go-tour content; check $GOROOT and $GOPATH")
}

func main() {
	flag.Parse()

	// find and serve the go tour files
	root, err := findRoot()
	if err != nil {
		log.Fatalf("Couldn't find tour files: %v", err)
	}

	log.Println("Serving content from", root)

	host, port, err := net.SplitHostPort(*httpListen)
	if err != nil {
		log.Fatal(err)
	}
	if host == "" {
		host = "localhost"
	}
	if host != "127.0.0.1" && host != "localhost" {
		log.Print(localhostWarning)
	}
	httpAddr = host + ":" + port

	if err := initTour(root); err != nil {
		log.Fatal(err)
	}

	fs := http.FileServer(http.Dir(root))
	http.Handle("/favicon.ico", fs)
	http.Handle("/static/", fs)
	http.Handle("/talks/", fs)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/" {
			if err := renderTour(w); err != nil {
				log.Println(err)
			}
			return
		}
		http.Error(w, "not found", 404)
	})

	http.Handle(socketPath, socket.Handler)

	err = serveScripts(filepath.Join(root, "js"), "SocketTransport")
	if err != nil {
		log.Fatal(err)
	}

	go func() {
		url := "http://" + httpAddr
		if waitServer(url) && *openBrowser && startBrowser(url) {
			log.Printf("A browser window should open. If not, please visit %s", url)
		} else {
			log.Printf("Please open your web browser and visit %s", url)
		}
	}()
	log.Fatal(http.ListenAndServe(httpAddr, nil))
}

const localhostWarning = `
WARNING!  WARNING!  WARNING!

I appear to be listening on an address that is not localhost.
Anyone with access to this address and port will have access
to this machine as the user running gotour.

If you don't understand this message, hit Control-C to terminate this process.

WARNING!  WARNING!  WARNING!
`

type response struct {
	Output string `json:"output"`
	Errors string `json:"compile_errors"`
}

func init() {
	socket.Environ = environ
}

// environ returns the original execution environment with GOPATH
// replaced (or added) with the value of the global var gopath.
func environ() (env []string) {
	for _, v := range os.Environ() {
		if !strings.HasPrefix(v, "GOPATH=") {
			env = append(env, v)
		}
	}
	env = append(env, "GOPATH="+gopath)
	return
}

// waitServer waits some time for the http Server to start
// serving url and returns whether it starts
func waitServer(url string) bool {
	tries := 20
	for tries > 0 {
		resp, err := http.Get(url)
		if err == nil {
			resp.Body.Close()
			return true
		}
		time.Sleep(100 * time.Millisecond)
		tries--
	}
	return false
}

// startBrowser tries to open the URL in a browser, and returns
// whether it succeed.
func startBrowser(url string) bool {
	// try to start the browser
	var args []string
	switch runtime.GOOS {
	case "darwin":
		args = []string{"open"}
	case "windows":
		args = []string{"cmd", "/c", "start"}
	default:
		args = []string{"xdg-open"}
	}
	cmd := exec.Command(args[0], append(args[1:], url)...)
	return cmd.Start() == nil
}

// prepContent for the local tour simply returns the content as-is.
func prepContent(r io.Reader) io.Reader { return r }

// socketAddr returns the WebSocket handler address.
func socketAddr() string { return "ws://" + httpAddr + socketPath }
<|endoftext|>


<commit_before>// Copyright 2013 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 godoc

import (
	"bytes"
	"reflect"
	"sort"
	"strings"
	"testing"

	"code.google.com/p/go.tools/godoc/vfs/mapfs"
)

func newCorpus(t *testing.T) *Corpus {
	c := NewCorpus(mapfs.New(map[string]string{
		"src/pkg/foo/foo.go": `// Package foo is an example.
package foo

import "bar"

const Pi = 3.1415

var Foos []Foo

// Foo is stuff.
type Foo struct{}

func New() *Foo {
   return new(Foo)
}
`,
		"src/pkg/bar/bar.go": `// Package bar is another example to test races.
package bar
`,
		"src/pkg/other/bar/bar.go": `// Package bar is another bar package.
package bar
func X() {}
`,
		"src/pkg/skip/skip.go": `// Package skip should be skipped.
package skip
func Skip() {}
`,
		"src/pkg/bar/readme.txt": `Whitelisted text file.
`,
		"src/pkg/bar/baz.zzz": `Text file not whitelisted.
`,
	}))
	c.IndexEnabled = true
	c.IndexDirectory = func(dir string) bool {
		return !strings.Contains(dir, "skip")
	}

	if err := c.Init(); err != nil {
		t.Fatal(err)
	}
	return c
}

func TestIndex(t *testing.T) {
	for _, docs := range []bool{true, false} {
		for _, goCode := range []bool{true, false} {
			for _, fullText := range []bool{true, false} {
				c := newCorpus(t)
				c.IndexDocs = docs
				c.IndexGoCode = goCode
				c.IndexFullText = fullText
				c.UpdateIndex()
				ix, _ := c.CurrentIndex()
				if ix == nil {
					t.Fatal("no index")
				}
				t.Logf("docs, goCode, fullText = %v,%v,%v", docs, goCode, fullText)
				testIndex(t, c, ix)
			}
		}
	}
}

func TestIndexWriteRead(t *testing.T) {
	type key struct {
		docs, goCode, fullText bool
	}
	type val struct {
		buf *bytes.Buffer
		c   *Corpus
	}
	m := map[key]val{}

	for _, docs := range []bool{true, false} {
		for _, goCode := range []bool{true, false} {
			for _, fullText := range []bool{true, false} {
				k := key{docs, goCode, fullText}
				c := newCorpus(t)
				c.IndexDocs = docs
				c.IndexGoCode = goCode
				c.IndexFullText = fullText
				c.UpdateIndex()
				ix, _ := c.CurrentIndex()
				if ix == nil {
					t.Fatal("no index")
				}
				var buf bytes.Buffer
				nw, err := ix.WriteTo(&buf)
				if err != nil {
					t.Fatalf("Index.WriteTo: %v", err)
				}
				m[k] = val{bytes.NewBuffer(buf.Bytes()), c}
				ix2 := new(Index)
				nr, err := ix2.ReadFrom(&buf)
				if err != nil {
					t.Fatalf("Index.ReadFrom: %v", err)
				}
				if nr != nw {
					t.Errorf("Wrote %d bytes to index but read %d", nw, nr)
				}
				testIndex(t, c, ix)
			}
		}
	}
	// Test CompatibleWith
	for k1, v1 := range m {
		ix := new(Index)
		if _, err := ix.ReadFrom(v1.buf); err != nil {
			t.Fatalf("Index.ReadFrom: %v", err)
		}
		for k2, v2 := range m {
			if got, want := ix.CompatibleWith(v2.c), k1 == k2; got != want {
				t.Errorf("CompatibleWith = %v; want %v for %v, %v", got, want, k1, k2)
			}
		}
	}
}

func testIndex(t *testing.T, c *Corpus, ix *Index) {
	if _, ok := ix.words["Skip"]; ok {
		t.Errorf("the word Skip was found; expected it to be skipped")
	}
	checkStats(t, c, ix)
	checkImportCount(t, c, ix)
	checkPackagePath(t, c, ix)
	checkExports(t, c, ix)
	checkIdents(t, c, ix)
}

// checkStats checks the Index's statistics.
// Some statistics are only set when we're indexing Go code.
func checkStats(t *testing.T, c *Corpus, ix *Index) {
	want := Statistics{}
	if c.IndexFullText {
		want.Bytes = 314
		want.Files = 4
		want.Lines = 21
	} else if c.IndexDocs || c.IndexGoCode {
		want.Bytes = 291
		want.Files = 3
		want.Lines = 20
	}
	if c.IndexGoCode {
		want.Words = 8
		want.Spots = 12
	}
	if got := ix.Stats(); !reflect.DeepEqual(got, want) {
		t.Errorf("Stats = %#v; want %#v", got, want)
	}
}

// checkImportCount checks the Index's import count map.
// It is only set when we're indexing Go code.
func checkImportCount(t *testing.T, c *Corpus, ix *Index) {
	want := map[string]int{}
	if c.IndexGoCode {
		want = map[string]int{
			"bar": 1,
		}
	}
	if got := ix.ImportCount(); !reflect.DeepEqual(got, want) {
		t.Errorf("ImportCount = %v; want %v", got, want)
	}
}

// checkPackagePath checks the Index's package path map.
// It is set if at least one of the indexing options is enabled.
func checkPackagePath(t *testing.T, c *Corpus, ix *Index) {
	want := map[string]map[string]bool{}
	if c.IndexDocs || c.IndexGoCode || c.IndexFullText {
		want = map[string]map[string]bool{
			"foo": map[string]bool{
				"foo": true,
			},
			"bar": map[string]bool{
				"bar":       true,
				"other/bar": true,
			},
		}
	}
	if got := ix.PackagePath(); !reflect.DeepEqual(got, want) {
		t.Errorf("PackagePath = %v; want %v", got, want)
	}
}

// checkExports checks the Index's exports map.
// It is only set when we're indexing Go code.
func checkExports(t *testing.T, c *Corpus, ix *Index) {
	want := map[string]map[string]SpotKind{}
	if c.IndexGoCode {
		want = map[string]map[string]SpotKind{
			"foo": map[string]SpotKind{
				"Pi":   ConstDecl,
				"Foos": VarDecl,
				"Foo":  TypeDecl,
				"New":  FuncDecl,
			},
			"other/bar": map[string]SpotKind{
				"X": FuncDecl,
			},
		}
	}
	if got := ix.Exports(); !reflect.DeepEqual(got, want) {
		t.Errorf("Exports = %v; want %v", got, want)
	}
}

// checkIdents checks the Index's indents map.
// It is only set when we're indexing documentation.
func checkIdents(t *testing.T, c *Corpus, ix *Index) {
	want := map[SpotKind]map[string][]Ident{}
	if c.IndexDocs {
		want = map[SpotKind]map[string][]Ident{
			ConstDecl: map[string][]Ident{
				"Pi": []Ident{{"/src/pkg/foo", "foo", "Pi", ""}},
			},
			VarDecl: map[string][]Ident{
				"Foos": []Ident{{"/src/pkg/foo", "foo", "Foos", ""}},
			},
			TypeDecl: map[string][]Ident{
				"Foo": []Ident{{"/src/pkg/foo", "foo", "Foo", "Foo is stuff."}},
			},
			FuncDecl: map[string][]Ident{
				"New": []Ident{{"/src/pkg/foo", "foo", "New", ""}},
				"X":   []Ident{{"/src/pkg/other/bar", "bar", "X", ""}},
			},
		}
	}
	if got := ix.Idents(); !reflect.DeepEqual(got, want) {
		t.Errorf("Idents = %v; want %v", got, want)
	}
}

func TestIdentResultSort(t *testing.T) {
	for _, tc := range []struct {
		ir  []Ident
		exp []Ident
	}{
		{
			ir: []Ident{
				{"/a/b/pkg2", "pkg2", "MyFunc2", ""},
				{"/b/d/pkg3", "pkg3", "MyFunc3", ""},
				{"/a/b/pkg1", "pkg1", "MyFunc1", ""},
			},
			exp: []Ident{
				{"/a/b/pkg1", "pkg1", "MyFunc1", ""},
				{"/a/b/pkg2", "pkg2", "MyFunc2", ""},
				{"/b/d/pkg3", "pkg3", "MyFunc3", ""},
			},
		},
	} {
		if sort.Sort(byPackage(tc.ir)); !reflect.DeepEqual(tc.ir, tc.exp) {
			t.Errorf("got: %v, want %v", tc.ir, tc.exp)
		}
	}
}

func TestIdentPackageFilter(t *testing.T) {
	for _, tc := range []struct {
		ir  []Ident
		pak string
		exp []Ident
	}{
		{
			ir: []Ident{
				{"/a/b/pkg2", "pkg2", "MyFunc2", ""},
				{"/b/d/pkg3", "pkg3", "MyFunc3", ""},
				{"/a/b/pkg1", "pkg1", "MyFunc1", ""},
			},
			pak: "pkg2",
			exp: []Ident{
				{"/a/b/pkg2", "pkg2", "MyFunc2", ""},
			},
		},
	} {
		if res := byPackage(tc.ir).filter(tc.pak); !reflect.DeepEqual(res, tc.exp) {
			t.Errorf("got: %v, want %v", res, tc.exp)
		}
	}
}
<commit_msg>godoc: Update identifier indexing tests.<commit_after>// Copyright 2013 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 godoc

import (
	"bytes"
	"reflect"
	"sort"
	"strings"
	"testing"

	"code.google.com/p/go.tools/godoc/vfs/mapfs"
)

func newCorpus(t *testing.T) *Corpus {
	c := NewCorpus(mapfs.New(map[string]string{
		"src/pkg/foo/foo.go": `// Package foo is an example.
package foo

import "bar"

const Pi = 3.1415

var Foos []Foo

// Foo is stuff.
type Foo struct{}

func New() *Foo {
   return new(Foo)
}
`,
		"src/pkg/bar/bar.go": `// Package bar is another example to test races.
package bar
`,
		"src/pkg/other/bar/bar.go": `// Package bar is another bar package.
package bar
func X() {}
`,
		"src/pkg/skip/skip.go": `// Package skip should be skipped.
package skip
func Skip() {}
`,
		"src/pkg/bar/readme.txt": `Whitelisted text file.
`,
		"src/pkg/bar/baz.zzz": `Text file not whitelisted.
`,
	}))
	c.IndexEnabled = true
	c.IndexDirectory = func(dir string) bool {
		return !strings.Contains(dir, "skip")
	}

	if err := c.Init(); err != nil {
		t.Fatal(err)
	}
	return c
}

func TestIndex(t *testing.T) {
	for _, docs := range []bool{true, false} {
		for _, goCode := range []bool{true, false} {
			for _, fullText := range []bool{true, false} {
				c := newCorpus(t)
				c.IndexDocs = docs
				c.IndexGoCode = goCode
				c.IndexFullText = fullText
				c.UpdateIndex()
				ix, _ := c.CurrentIndex()
				if ix == nil {
					t.Fatal("no index")
				}
				t.Logf("docs, goCode, fullText = %v,%v,%v", docs, goCode, fullText)
				testIndex(t, c, ix)
			}
		}
	}
}

func TestIndexWriteRead(t *testing.T) {
	type key struct {
		docs, goCode, fullText bool
	}
	type val struct {
		buf *bytes.Buffer
		c   *Corpus
	}
	m := map[key]val{}

	for _, docs := range []bool{true, false} {
		for _, goCode := range []bool{true, false} {
			for _, fullText := range []bool{true, false} {
				k := key{docs, goCode, fullText}
				c := newCorpus(t)
				c.IndexDocs = docs
				c.IndexGoCode = goCode
				c.IndexFullText = fullText
				c.UpdateIndex()
				ix, _ := c.CurrentIndex()
				if ix == nil {
					t.Fatal("no index")
				}
				var buf bytes.Buffer
				nw, err := ix.WriteTo(&buf)
				if err != nil {
					t.Fatalf("Index.WriteTo: %v", err)
				}
				m[k] = val{bytes.NewBuffer(buf.Bytes()), c}
				ix2 := new(Index)
				nr, err := ix2.ReadFrom(&buf)
				if err != nil {
					t.Fatalf("Index.ReadFrom: %v", err)
				}
				if nr != nw {
					t.Errorf("Wrote %d bytes to index but read %d", nw, nr)
				}
				testIndex(t, c, ix)
			}
		}
	}
	// Test CompatibleWith
	for k1, v1 := range m {
		ix := new(Index)
		if _, err := ix.ReadFrom(v1.buf); err != nil {
			t.Fatalf("Index.ReadFrom: %v", err)
		}
		for k2, v2 := range m {
			if got, want := ix.CompatibleWith(v2.c), k1 == k2; got != want {
				t.Errorf("CompatibleWith = %v; want %v for %v, %v", got, want, k1, k2)
			}
		}
	}
}

func testIndex(t *testing.T, c *Corpus, ix *Index) {
	if _, ok := ix.words["Skip"]; ok {
		t.Errorf("the word Skip was found; expected it to be skipped")
	}
	checkStats(t, c, ix)
	checkImportCount(t, c, ix)
	checkPackagePath(t, c, ix)
	checkExports(t, c, ix)
	checkIdents(t, c, ix)
}

// checkStats checks the Index's statistics.
// Some statistics are only set when we're indexing Go code.
func checkStats(t *testing.T, c *Corpus, ix *Index) {
	want := Statistics{}
	if c.IndexFullText {
		want.Bytes = 314
		want.Files = 4
		want.Lines = 21
	} else if c.IndexDocs || c.IndexGoCode {
		want.Bytes = 291
		want.Files = 3
		want.Lines = 20
	}
	if c.IndexGoCode {
		want.Words = 8
		want.Spots = 12
	}
	if got := ix.Stats(); !reflect.DeepEqual(got, want) {
		t.Errorf("Stats = %#v; want %#v", got, want)
	}
}

// checkImportCount checks the Index's import count map.
// It is only set when we're indexing Go code.
func checkImportCount(t *testing.T, c *Corpus, ix *Index) {
	want := map[string]int{}
	if c.IndexGoCode {
		want = map[string]int{
			"bar": 1,
		}
	}
	if got := ix.ImportCount(); !reflect.DeepEqual(got, want) {
		t.Errorf("ImportCount = %v; want %v", got, want)
	}
}

// checkPackagePath checks the Index's package path map.
// It is set if at least one of the indexing options is enabled.
func checkPackagePath(t *testing.T, c *Corpus, ix *Index) {
	want := map[string]map[string]bool{}
	if c.IndexDocs || c.IndexGoCode || c.IndexFullText {
		want = map[string]map[string]bool{
			"foo": map[string]bool{
				"foo": true,
			},
			"bar": map[string]bool{
				"bar":       true,
				"other/bar": true,
			},
		}
	}
	if got := ix.PackagePath(); !reflect.DeepEqual(got, want) {
		t.Errorf("PackagePath = %v; want %v", got, want)
	}
}

// checkExports checks the Index's exports map.
// It is only set when we're indexing Go code.
func checkExports(t *testing.T, c *Corpus, ix *Index) {
	want := map[string]map[string]SpotKind{}
	if c.IndexGoCode {
		want = map[string]map[string]SpotKind{
			"foo": map[string]SpotKind{
				"Pi":   ConstDecl,
				"Foos": VarDecl,
				"Foo":  TypeDecl,
				"New":  FuncDecl,
			},
			"other/bar": map[string]SpotKind{
				"X": FuncDecl,
			},
		}
	}
	if got := ix.Exports(); !reflect.DeepEqual(got, want) {
		t.Errorf("Exports = %v; want %v", got, want)
	}
}

// checkIdents checks the Index's indents map.
// It is only set when we're indexing documentation.
func checkIdents(t *testing.T, c *Corpus, ix *Index) {
	want := map[SpotKind]map[string][]Ident{}
	if c.IndexDocs {
		want = map[SpotKind]map[string][]Ident{
			PackageClause: map[string][]Ident{
				"bar": []Ident{
					{"/src/pkg/bar", "bar", "bar", "Package bar is another example to test races."},
					{"/src/pkg/other/bar", "bar", "bar", "Package bar is another bar package."},
				},
				"foo": []Ident{{"/src/pkg/foo", "foo", "foo", "Package foo is an example."}},
			},
			ConstDecl: map[string][]Ident{
				"Pi": []Ident{{"/src/pkg/foo", "foo", "Pi", ""}},
			},
			VarDecl: map[string][]Ident{
				"Foos": []Ident{{"/src/pkg/foo", "foo", "Foos", ""}},
			},
			TypeDecl: map[string][]Ident{
				"Foo": []Ident{{"/src/pkg/foo", "foo", "Foo", "Foo is stuff."}},
			},
			FuncDecl: map[string][]Ident{
				"New": []Ident{{"/src/pkg/foo", "foo", "New", ""}},
				"X":   []Ident{{"/src/pkg/other/bar", "bar", "X", ""}},
			},
		}
	}
	if got := ix.Idents(); !reflect.DeepEqual(got, want) {
		t.Errorf("Idents = %v; want %v", got, want)
	}
}

func TestIdentResultSort(t *testing.T) {
	for _, tc := range []struct {
		ir  []Ident
		exp []Ident
	}{
		{
			ir: []Ident{
				{"/a/b/pkg2", "pkg2", "MyFunc2", ""},
				{"/b/d/pkg3", "pkg3", "MyFunc3", ""},
				{"/a/b/pkg1", "pkg1", "MyFunc1", ""},
			},
			exp: []Ident{
				{"/a/b/pkg1", "pkg1", "MyFunc1", ""},
				{"/a/b/pkg2", "pkg2", "MyFunc2", ""},
				{"/b/d/pkg3", "pkg3", "MyFunc3", ""},
			},
		},
	} {
		if sort.Sort(byPackage(tc.ir)); !reflect.DeepEqual(tc.ir, tc.exp) {
			t.Errorf("got: %v, want %v", tc.ir, tc.exp)
		}
	}
}

func TestIdentPackageFilter(t *testing.T) {
	for _, tc := range []struct {
		ir  []Ident
		pak string
		exp []Ident
	}{
		{
			ir: []Ident{
				{"/a/b/pkg2", "pkg2", "MyFunc2", ""},
				{"/b/d/pkg3", "pkg3", "MyFunc3", ""},
				{"/a/b/pkg1", "pkg1", "MyFunc1", ""},
			},
			pak: "pkg2",
			exp: []Ident{
				{"/a/b/pkg2", "pkg2", "MyFunc2", ""},
			},
		},
	} {
		if res := byPackage(tc.ir).filter(tc.pak); !reflect.DeepEqual(res, tc.exp) {
			t.Errorf("got: %v, want %v", res, tc.exp)
		}
	}
}
<|endoftext|>


<commit_before>//=====================================================================
//
// ragesocks.go -
//
// Created by skywind on 2018/03/01
// Last Modified: 2018/03/01 23:52:50
//
//=====================================================================
// vim: set ts=4 sw=4 tw=0 noet fdm=indent foldlevel=99 :

package main

import (
	"flag"
	"log"
	"crypto/rc4"
	"strconv"
	"net"
	"io"
	// "os"
)

//---------------------------------------------------------------------
// config
//---------------------------------------------------------------------
type Config struct {
	run_mode string
	server_host string
	client_host string
	server_port int
	client_port int
	key string
	method string
}

var config = Config {}

//---------------------------------------------------------------------
// Protocol
//---------------------------------------------------------------------
type Protocol struct {
	crypt_send *rc4.Cipher
	crypt_recv *rc4.Cipher
	twice_send *rc4.Cipher
	twice_recv *rc4.Cipher
	conn *net.TCPConn
	esock *net.TCPConn
	remote_address string
}

//---------------------------------------------------------------------
// arguments_init()
//---------------------------------------------------------------------
func arguments_init() bool {
	server := flag.Bool("server", false, "Running mode")
	server_host := flag.String("s", "", "Server address")
	client_host := flag.String("b", "", "Local address")
	server_port := flag.Int("p", 1030, "Server port")
	client_port := flag.Int("l", 1030, "Client port")
	method := flag.String("m", "rc4", "Encryption method")
	key := flag.String("k", "", "Key string")
	flag.Parse()
	config.run_mode = "client"
	if *server {
		config.run_mode = "server"
	}
	config.server_host = *server_host
	config.client_host = *client_host
	config.server_port = *server_port
	config.client_port = *client_port
	config.method = *method
	config.key = *key
	if config.run_mode == "server" {
		if config.server_host == "" {
			config.server_host = "0.0.0.0"
		}
	}	else {
		if config.server_host == "" {
			log.Print("ERROR: empty server address, use -h to help")
			return false
		}
		if config.client_host == "" {
			config.client_host = "localhost"
		}
	}
	log.Print("[config] running mode: ", config.run_mode)
	log.Print("[config] server address: ", config.server_host)
	log.Print("[config] server port: ", config.server_port)
	log.Print("[config] client address: ", config.client_host)
	log.Print("[config] client port: ", config.client_port)
	return true
}

//---------------------------------------------------------------------
// handle error
//---------------------------------------------------------------------
func handle_error(err error) bool {
	if err == nil {
		return true
	}
	log.Printf("ERROR: %s", err.Error());
	return false
}

//---------------------------------------------------------------------
// main()
//---------------------------------------------------------------------
func main() {
	if !arguments_init() {
		return
	}

	endpoint := ""

	if config.run_mode == "server" {
		endpoint = config.server_host + ":" + strconv.Itoa(config.server_port)
	}	else {
		endpoint = config.client_host + ":" + strconv.Itoa(config.client_port)
	}

	addr, err := net.ResolveTCPAddr("tcp4", endpoint)
	if !handle_error(err) {
		return
	}

	listener, err := net.ListenTCP("tcp4", addr)
	if !handle_error(err) {
		return
	}

	log.Printf("%s is listening on %s", config.run_mode, endpoint)

	for {
		conn, err := listener.AcceptTCP()
		if err == nil {
			key := []byte(config.key)
			protocol := Protocol {}
			protocol.crypt_recv, _ = rc4.NewCipher(key)
			protocol.crypt_send, _ = rc4.NewCipher(key)
			protocol.twice_recv = nil
			protocol.twice_send = nil
			protocol.conn = conn
			protocol.esock = nil
			protocol.remote_address = ""
			if config.run_mode == "server" {
				protocol.esock = conn
				go func (protocol *Protocol) {
					defer protocol.conn.Close()
					handle_server(protocol)
				}(&protocol)
			}	else {
				go func (protocol *Protocol) {
					defer protocol.conn.Close()
					handle_client(protocol)
				}(&protocol)
			}
		}	else {
			handle_error(err)
		}
	}
}

//---------------------------------------------------------------------
// encryption send
//---------------------------------------------------------------------
func encrypt_send(protocol *Protocol, buf []byte) (int, error) {
	if (protocol.crypt_send != nil) {
		protocol.crypt_send.XORKeyStream(buf, buf)
	}
	if (protocol.twice_send != nil) {
		protocol.twice_send.XORKeyStream(buf, buf)
	}
	return protocol.esock.Write(buf)
}

//---------------------------------------------------------------------
// encryption recv
//---------------------------------------------------------------------
func encrypt_recv(protocol *Protocol, buf []byte) (int, error) {
	n, err := protocol.esock.Read(buf)
	if err != nil {
		return n, err
	}
	if (protocol.twice_recv != nil) {
		protocol.twice_recv.XORKeyStream(buf[:n], buf[:n])
	}
	if (protocol.crypt_recv != nil) {
		protocol.crypt_recv.XORKeyStream(buf[:n], buf[:n])
	}
	return n, nil
}

//---------------------------------------------------------------------
// encryption recv all
//---------------------------------------------------------------------
func encrypt_recv_all(protocol *Protocol, buf []byte) (int, error) {
	n, err := io.ReadFull(protocol.esock, buf)
	if err != nil {
		return n, err
	}
	if (protocol.twice_recv != nil) {
		protocol.twice_recv.XORKeyStream(buf, buf)
	}
	if (protocol.crypt_recv != nil) {
		protocol.crypt_recv.XORKeyStream(buf, buf)
	}
	return n, err
}

//---------------------------------------------------------------------
// server entry
//---------------------------------------------------------------------
func handle_server(protocol *Protocol) {
}

//---------------------------------------------------------------------
// client entry
//---------------------------------------------------------------------
func handle_client(protocol *Protocol) {
}

<commit_msg>update<commit_after>//=====================================================================
//
// ragesocks.go -
//
// Created by skywind on 2018/03/01
// Last Modified: 2018/03/01 23:52:50
//
//=====================================================================
// vim: set ts=4 sw=4 tw=0 noet fdm=indent foldlevel=99 :

package main

import (
	"flag"
	"log"
	"crypto/rc4"
	"strconv"
	"net"
	"io"
	// "os"
)

//---------------------------------------------------------------------
// config
//---------------------------------------------------------------------
type Config struct {
	run_mode string
	server_host string
	client_host string
	server_port int
	client_port int
	key string
	method string
}

var config = Config {}

//---------------------------------------------------------------------
// Protocol
//---------------------------------------------------------------------
type Protocol struct {
	crypt_send *rc4.Cipher
	crypt_recv *rc4.Cipher
	twice_send *rc4.Cipher
	twice_recv *rc4.Cipher
	conn *net.TCPConn
	esock *net.TCPConn
	remote_address string
}

//---------------------------------------------------------------------
// arguments_init()
//---------------------------------------------------------------------
func arguments_init() bool {
	server := flag.Bool("server", false, "Running mode")
	server_host := flag.String("s", "", "Server address")
	client_host := flag.String("b", "", "Local address")
	server_port := flag.Int("p", 1030, "Server port")
	client_port := flag.Int("l", 1030, "Client port")
	method := flag.String("m", "rc4", "Encryption method")
	key := flag.String("k", "", "Key string")
	flag.Parse()
	config.run_mode = "client"
	if *server {
		config.run_mode = "server"
	}
	config.server_host = *server_host
	config.client_host = *client_host
	config.server_port = *server_port
	config.client_port = *client_port
	config.method = *method
	config.key = *key
	if config.run_mode == "server" {
		if config.server_host == "" {
			config.server_host = "0.0.0.0"
		}
	}	else {
		if config.server_host == "" {
			log.Print("ERROR: empty server address, use -h to help")
			return false
		}
		if config.client_host == "" {
			config.client_host = "localhost"
		}
	}
	log.Print("[config] running mode: ", config.run_mode)
	log.Print("[config] server address: ", config.server_host)
	log.Print("[config] server port: ", config.server_port)
	log.Print("[config] client address: ", config.client_host)
	log.Print("[config] client port: ", config.client_port)
	return true
}

//---------------------------------------------------------------------
// handle error
//---------------------------------------------------------------------
func handle_error(err error) bool {
	if err == nil {
		return true
	}
	log.Printf("ERROR: %s", err.Error());
	return false
}

//---------------------------------------------------------------------
// main()
//---------------------------------------------------------------------
func main() {
	if !arguments_init() {
		return
	}

	endpoint := ""

	if config.run_mode == "server" {
		endpoint = config.server_host + ":" + strconv.Itoa(config.server_port)
	}	else {
		endpoint = config.client_host + ":" + strconv.Itoa(config.client_port)
	}

	addr, err := net.ResolveTCPAddr("tcp4", endpoint)
	if !handle_error(err) {
		return
	}

	listener, err := net.ListenTCP("tcp4", addr)
	if !handle_error(err) {
		return
	}

	log.Printf("%s is listening on %s", config.run_mode, endpoint)

	for {
		conn, err := listener.AcceptTCP()
		if err == nil {
			key := []byte(config.key)
			protocol := Protocol {}
			protocol.crypt_recv, _ = rc4.NewCipher(key)
			protocol.crypt_send, _ = rc4.NewCipher(key)
			protocol.twice_recv = nil
			protocol.twice_send = nil
			protocol.conn = conn
			protocol.esock = nil
			protocol.remote_address = ""
			if config.run_mode == "server" {
				protocol.esock = conn
				go func (protocol *Protocol) {
					defer protocol.conn.Close()
					handle_server(protocol)
				}(&protocol)
			}	else {
				go func (protocol *Protocol) {
					defer protocol.conn.Close()
					handle_client(protocol)
				}(&protocol)
			}
		}	else {
			handle_error(err)
		}
	}
}

//---------------------------------------------------------------------
// encryption send
//---------------------------------------------------------------------
func encrypt_send(protocol *Protocol, buf []byte) (int, error) {
	if (protocol.crypt_send != nil) {
		protocol.crypt_send.XORKeyStream(buf, buf)
	}
	if (protocol.twice_send != nil) {
		protocol.twice_send.XORKeyStream(buf, buf)
	}
	return protocol.esock.Write(buf)
}

//---------------------------------------------------------------------
// encryption recv
//---------------------------------------------------------------------
func encrypt_recv(protocol *Protocol, buf []byte) (int, error) {
	n, err := protocol.esock.Read(buf)
	if err != nil {
		return n, err
	}
	if (protocol.twice_recv != nil) {
		protocol.twice_recv.XORKeyStream(buf[:n], buf[:n])
	}
	if (protocol.crypt_recv != nil) {
		protocol.crypt_recv.XORKeyStream(buf[:n], buf[:n])
	}
	return n, nil
}

//---------------------------------------------------------------------
// encryption recv all
//---------------------------------------------------------------------
func encrypt_recv_all(protocol *Protocol, buf []byte) (int, error) {
	n, err := io.ReadFull(protocol.esock, buf)
	if err != nil {
		return n, err
	}
	if (protocol.twice_recv != nil) {
		protocol.twice_recv.XORKeyStream(buf, buf)
	}
	if (protocol.crypt_recv != nil) {
		protocol.crypt_recv.XORKeyStream(buf, buf)
	}
	return n, err
}

//---------------------------------------------------------------------
// client entry
//---------------------------------------------------------------------
func handle_client(protocol *Protocol) {
}

//---------------------------------------------------------------------
// server entry
//---------------------------------------------------------------------
func handle_server(protocol *Protocol) {
}

<|endoftext|>