Example #1
0
func RestGetPuzzle(name string) {
	log.Logf(l4g.DEBUG, "RestGetPuzzle: requesting token to fetch %v", name)
	httpRestReqLimiter <- 1 // put a token in the limiting channel
	defer func() {
		log.Logf(l4g.DEBUG, "RestGetPuzzle: releasing token from fetching %v", name)
		<-httpRestReqLimiter // release a token from the limiting channel
	}()

	log.Logf(l4g.DEBUG, "RestGetPuzzle: preparing request for %v", name)
	//client := restclient.New()
	req := restclient.RestRequest{
		Url:    pbRestUri + "/puzzles/" + name,
		Method: restclient.GET,
		Result: new(Puzzle),
	}
	log.Logf(l4g.DEBUG, "RestGetPuzzle: sending request for %v", name)
	status, err := client.Do(&req)
	if err != nil {
		log.Logf(l4g.ERROR, "RestGetPuzzle: error %v", err)
		// TODO: do something... retry?
		l4g.Crashf("RestGetPuzzle: could not get puzzle [%v] - bailing out", name)
	}
	log.Logf(l4g.DEBUG, "RestGetPuzzle: received response for %v", name)
	if status == 200 {
		// send result on puzzleChan
		log.Logf(l4g.DEBUG, "RestGetPuzzle: sending puzzle on puzzleChan for %v", name)
		puzzleChan <- req.Result.(*Puzzle)
	} else {
		log.Logf(l4g.ERROR, "RestGetPuzzle: got status %v", status)
		// TODO: do something... retry?
		l4g.Crashf("RestGetPuzzle: could not get puzzle [%v] - bailing out", name)
	}
}
Example #2
0
func OpenDrive(googleClientId string, googleClientSecret string, googleDomain string, cacheFile string) {
	googleWriterDomain = googleDomain
	GcacheFile = cacheFile
	GgoogleClientId = googleClientId
	GgoogleClientSecret = googleClientSecret

	// Settings for Google authorization.
	oauthConfig := &oauth.Config{
		ClientId:     googleClientId,
		ClientSecret: googleClientSecret,
		Scope:        "https://www.googleapis.com/auth/drive",
		RedirectURL:  "urn:ietf:wg:oauth:2.0:oob",
		AuthURL:      "https://accounts.google.com/o/oauth2/auth",
		TokenURL:     "https://accounts.google.com/o/oauth2/token",
		TokenCache:   oauth.CacheFile(cacheFile),
	}

	// Set up a Transport using the oauthConfig.
	oauthTransport = &oauth.Transport{
		Config:    oauthConfig,
		Transport: http.DefaultTransport,
	}

	// Try to pull the token from the cache; if this fails, we need to get one.
	token, err := oauthConfig.TokenCache.Token()
	if err != nil {
		// Get an authorization code from the user
		authUrl := oauthConfig.AuthCodeURL("state")
		log.Logf(l4g.INFO, "Go to the following link in your browser: %v", authUrl)

		// Read the code, and exchange it for a token.
		log.Logf(l4g.INFO, "Enter verification code: ")
		var code string
		fmt.Scanln(&code)
		token, err = oauthTransport.Exchange(code)
		if err != nil {
			l4g.Crashf("An error occurred exchanging the code: %v", err)
		}
		log.Logf(l4g.INFO, "Token is cached in %v", oauthConfig.TokenCache)
	}

	oauthTransport.Token = token

	oauthClient = oauthTransport.Client()

	// Create a new authorized Drive client.
	driveSvc, err = drive.New(oauthClient)
	if err != nil {
		l4g.Crashf("An error occurred creating Drive client: %v", err)
	}
}
Example #3
0
func startHttpControl() {
	// Start an http server for control
	http.HandleFunc("/"+httpControlPath+"/", func(w http.ResponseWriter, r *http.Request) {
		if r.Method == "POST" {
			log.Logf(l4g.INFO, "Got POST on control port to %v", html.EscapeString(r.URL.Path))

			switch r.URL.Path {
			case "/" + httpControlPath + "/version":
				{
					defer r.Body.Close()
					var data BigJimmyControlData
					err := json.NewDecoder(r.Body).Decode(&data)
					if err != nil {
						log.Logf(l4g.ERROR, "Error decoding JSON from body of POST: %v", err)
						w.WriteHeader(http.StatusBadRequest)
						fmt.Fprintf(w, "Error decoding JSON from body of POST: %v", err)
					}
					log.Logf(l4g.INFO, "Processed data from version POST: %+v", data)

					newVersion, err := strconv.ParseInt(data.Version, 10, 0)
					if err != nil {
						log.Logf(l4g.ERROR, "Could not parse version as int: %v", err)
						w.WriteHeader(http.StatusBadRequest)
						fmt.Fprintf(w, "Could not parse version as int: %v", err)

					}

					if newVersion > Version {
						// get and process version diff
						//go PbGetVersionDiff(Version)
						// send the version down the channel for processing
						versionChan <- newVersion
					}
					w.WriteHeader(http.StatusOK)
					fmt.Fprintf(w, "Processed version POST: %+v", data)

				}
			default:
				{
					w.WriteHeader(http.StatusNotFound)

					fmt.Fprintf(w, "Got POST on control port to %v", html.EscapeString(r.URL.Path))
				}
			}
		} else {
			log.Logf(l4g.ERROR, "method %v not supported on control port (requested %v)", r.Method, html.EscapeString(r.URL.Path))
			w.WriteHeader(http.StatusNotImplemented)
			fmt.Fprintf(w, "method %v not supported on control port (requested %v)", r.Method, html.EscapeString(r.URL.Path))
		}
	})
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotFound)
		log.Logf(l4g.ERROR, "returning StatusNotFound (requested %v)", html.EscapeString(r.URL.Path))
	})

	log.Logf(l4g.INFO, "starting http server on port %v", httpControlPort)
	l4g.Crashf("http server died: %v", http.ListenAndServe(":"+httpControlPort, nil))
}
Example #4
0
// Open/Close DB
func OpenDB(dbUser string, dbPassword string, dbProtocol string, dbHost string, dbPort string, dbName string) {
	// Connect to database
	mysqlDsn := dbUser + ":" + dbPassword + "@" + dbProtocol + "(" + dbHost + ":" + dbPort + ")/" + dbName
	var err error
	dbCon, err = sql.Open("mysql", mysqlDsn)
	if err != nil {
		l4g.Crashf("could not connect to mysql database with DSN %v: %v", mysqlDsn, err)
	}
}
Example #5
0
func init() {
	roundChan = make(chan *Round, 10)
	restGetRoundsDone = make(chan int) // must not be buffered!
	rounds = make(map[string]*Round, 500)

	// get rounds from roundChan and shovel them into rounds map
	go func() {
		for true {
			log.Logf(l4g.TRACE, "roundChan listener: waiting for new round")
			round := <-roundChan // this will block waiting for new rounds
			log.Logf(l4g.INFO, "roundChan listener: got new round %+v", round)

			if round.Drive_id == "" {
				// don't have a drive_id for this round
				// create round folder in Google Drive
				roundFolderId, roundFolderUri, err := CreateRound(round.Name, huntFolderId)
				if err != nil {
					log.Logf(l4g.ERROR, "roundChan listener: could not create round [%v] in huntFolderId=[%v]: %v", round.Name, huntFolderId, err)
					// retry 3 times
					retry := 3
					for err != nil && retry > 0 {
						// set timer
						roundWaitTimer := time.NewTimer(500 * time.Millisecond)
						// block on timer channel
						<-roundWaitTimer.C
						log.Logf(l4g.ERROR, "roundChan listener: retrying CreateRound(%v, %v)", round.Name, huntFolderId)
						roundFolderId, roundFolderUri, err = CreateRound(round.Name, huntFolderId)

					}
					if err != nil {
						l4g.Crashf("roundChan listener: retried CreateRound(%v, %v) 3 times and all failed -- bailing out!", round.Name, huntFolderId)
					}
				}
				// creation should have succeeded

				// update local and remote drive_id and drive_uri
				round.Drive_id = roundFolderId
				go PbRestPost("rounds/"+round.Name+"/drive_id", PartPost{Data: roundFolderId})
				round.Drive_uri = roundFolderUri
				go PbRestPost("rounds/"+round.Name+"/drive_uri", PartPost{Data: roundFolderUri})
			}

			rounds[round.Name] = round
			roundsArrived++

			log.Logf(l4g.DEBUG, "roundChan listener: %v >= %v ?", roundsArrived, RoundCount)
			if roundsArrived >= RoundCount {
				restGetRoundsDone <- 1
			}

			// start a bigjimmy google drive monitor for this round (if we needed round folder monitoring)
			// BigJimmyRoundActivityMonitor(round)
		}
	}()
}
Example #6
0
// Run starts the web application and serves HTTP requests for s
func (s *Server) Run(addr string) {
	s.initServer()

	mux := http.NewServeMux()
	if s.Config.Profiler {
		mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
		mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
		mux.Handle("/debug/pprof/heap", pprof.Handler("heap"))
		mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
	}
	mux.Handle("/", s)

	s.Logger.Info("web.go serving %s", addr)

	l, err := net.Listen("tcp", addr)
	if err != nil {
		l4g.Crashf("ListenAndServe: %s", err)
	}
	s.l = l
	err = http.Serve(s.l, mux)
	s.l.Close()
}
func main() {
	flag.Parse()

	// Initialize logger
	logLevel = strings.ToLower(logLevel)
	switch {
	case logLevel == "trace":
		log = l4g.NewDefaultLogger(l4g.TRACE)
	case logLevel == "debug":
		log = l4g.NewDefaultLogger(l4g.DEBUG)
	case logLevel == "info":
		log = l4g.NewDefaultLogger(l4g.INFO)
	case logLevel == "warning":
		log = l4g.NewDefaultLogger(l4g.WARNING)
	case logLevel == "error":
		log = l4g.NewDefaultLogger(l4g.ERROR)
	}
	//log.AddFilter("log", l4g.FINE, l4g.NewFileLogWriter("example.log", true))
	bigjimmybot.SetLog(log)

	// Connect to DB
	log.Logf(l4g.TRACE, "main(): before OpenDB, %v goroutines.", runtime.NumGoroutine())
	bigjimmybot.OpenDB(dbUser, dbPassword, dbProtocol, dbHost, dbPort, dbName)
	defer bigjimmybot.CloseDB()
	log.Logf(l4g.TRACE, "main(): after OpenDB, %v goroutines.", runtime.NumGoroutine())

	var err error

	// Connect to Drive
	// Ensure we have googleClientId and googleClientSecret (from command-line args or DB)
	log.Logf(l4g.TRACE, "main(): before getting client id and secret, %v goroutines.", runtime.NumGoroutine())
	if googleClientId == "" {
		googleClientId, err = bigjimmybot.DbGetConfig("GOOGLE_CLIENT_ID")
		if err != nil {
			log.Logf(l4g.ERROR, "attempt to get googleClientId from DB failed: %v", err)
		}
	}
	if googleClientSecret == "" {
		googleClientSecret, err = bigjimmybot.DbGetConfig("GOOGLE_CLIENT_SECRET")
		if err != nil {
			log.Logf(l4g.ERROR, "attempt to get googleClientSecret from DB failed: %v", err)
		}
	}
	if googleClientId == "" || googleClientSecret == "" {
		log.Logf(l4g.ERROR, "Please specify -google_client_id and -google_client_secret (or ensure they are in the DB and database connection is working)")
		flag.Usage()
		l4g.Crashf(usageMsg)
	} else {
		log.Logf(l4g.INFO, "Using google_client_id=%v and google_client_secret=%v", googleClientId, googleClientSecret)
	}
	// Try to get google_domain (for permissions) from DB
	if googleDomain == "" {
		googleDomain, err = bigjimmybot.DbGetConfig("GOOGLE_DOMAIN")
		if err != nil {
			l4g.Crashf("Could not get pb_rest_uri from DB: %v", err)
		}
	}
	log.Logf(l4g.TRACE, "main(): before open drive, %v goroutines.", runtime.NumGoroutine())
	bigjimmybot.OpenDrive(googleClientId, googleClientSecret, googleDomain, cacheFile)
	log.Logf(l4g.TRACE, "main(): after open drive, %v goroutines.", runtime.NumGoroutine())

	// Setup PB REST client
	// Get pbRestUri if we don't have it
	if pbRestUri == "" {
		pbRestUri, err = bigjimmybot.DbGetConfig("PB_REST_URI")
		if err != nil {
			l4g.Crashf("Could not get pb_rest_uri from DB: %v", err)
		}
	}
	bigjimmybot.SetPbRestUri(pbRestUri)

	// Get huntFolderId (either from command-line, from database, or from Google Drive if we have title)
	// Ensure we can get huntFolderId (from command-line arg, DB, or via huntFolderTitle)
	if huntFolderId == "" {
		huntFolderId, _ = bigjimmybot.DbGetConfig("google_hunt_folder_id")
	}
	if huntFolderId == "" && huntFolderTitle == "" {
		// still don't have huntFolderId, and we don't have title either
		// try to get title from DB
		huntFolderTitle, _ = bigjimmybot.DbGetConfig("PB_HUNT")
	} else if huntFolderId != "" && huntFolderTitle != "" {
		log.Logf(l4g.INFO, "you specified hunt_folder_title but we have hunt_folder_id so it is being ignored.")
		huntFolderTitle = ""
	}
	log.Logf(l4g.TRACE, "main(): before getting hunt folder id, %v goroutines.", runtime.NumGoroutine())
	if huntFolderId == "" && huntFolderTitle != "" {
		// huntFolderId neither specified nor in DB, but we do have title
		// so get hunt folder ID from Google by looking it up by title
		// or create it if it does not exist
		log.Logf(l4g.INFO, "looking up google docs folder id for title %v", huntFolderTitle)
		huntFolderId, err = bigjimmybot.GetFolderIdByTitle(huntFolderTitle)
		if err != nil {
			if err, ok := err.(*bigjimmybot.ListError); ok {
				if err.Found > 1 {
					l4g.Crashf("more than one document matches %v", huntFolderTitle)
				} else if err.Found == 0 {
					//l4g.Crashf("no hunt folder found for %v", huntFolderTitle)
					log.Logf(l4g.INFO, "no hunt folder found for %v, creating it", huntFolderTitle)
					var cferr error
					huntFolderId, _, cferr = bigjimmybot.CreateHunt(huntFolderTitle)
					if cferr != nil {
						l4g.Crashf("could not create hunt folder for title [%v]: %v", huntFolderTitle, cferr)
					}
					log.Logf(l4g.INFO, "hunt folder created")
				}
			} else {
				l4g.Crashf("an error occurred getting hunt folder ID: %v", err)
			}
		}
		log.Logf(l4g.INFO, "hunt_folder_id: %v", huntFolderId)
		// DB doesn't yet have huntFolderId, set it if we have it
		if huntFolderId != "" {
			err = bigjimmybot.DbSetConfig("google_hunt_folder_id", huntFolderId)
			if err != nil {
				l4g.Crashf("could not set hunt_folder_id in DB")
			}
		}
	}
	log.Logf(l4g.TRACE, "main(): after getting hunt folder id, %v goroutines.", runtime.NumGoroutine())
	// set huntFolderId in bigjimmybot
	bigjimmybot.SetHuntFolderId(huntFolderId)

	// get initial version diff
	log.Logf(l4g.TRACE, "main(): before bigjimmybot.PbGetInitialVersionDiff %v goroutines.", runtime.NumGoroutine())
	bigjimmybot.PbGetInitialVersionDiff()
	log.Logf(l4g.TRACE, "main(): after bigjimmybot.PbGetInitialVersionDiff %v goroutines.", runtime.NumGoroutine())

	// Start ControlServer main loop
	// Ensure we have httpControlPort and httpControlPath
	log.Logf(l4g.TRACE, "main(): before ensuring httpControlPort and httpControlPath %v goroutines.", runtime.NumGoroutine())
	if httpControlPort == "" {
		httpControlPort, err = bigjimmybot.DbGetConfig("BIGJIMMY_CONTROL_PORT")
		if err != nil {
			log.Logf(l4g.ERROR, "attempt to get httpControlPort from DB failed: %v", err)
		}
	}
	if httpControlPath == "" {
		httpControlPath, err = bigjimmybot.DbGetConfig("BIGJIMMY_CONTROL_PATH")
		if err != nil {
			log.Logf(l4g.ERROR, "attempt to get httpControlPath from DB failed: %v", err)
		}
	}
	if httpControlPort == "" || httpControlPath == "" {
		log.Logf(l4g.ERROR, "Please specify -http_control_port and -http_control_path (or ensure they are in the DB and database connection is working)")
		flag.Usage()
		l4g.Crashf(usageMsg)
	} else {
		log.Logf(l4g.INFO, "Using http_control_port=%v and http_control_path=%v", httpControlPort, httpControlPath)
	}
	log.Logf(l4g.TRACE, "main(): after ensuring httpControlPort and httpControlPath %v goroutines.", runtime.NumGoroutine())

	time.Sleep(5 * time.Second)
	log.Logf(l4g.TRACE, "main(): before bigjimmybot.ControlServer %v goroutines.", runtime.NumGoroutine())
	bigjimmybot.ControlServer(httpControlPort, httpControlPath)
	log.Logf(l4g.TRACE, "main(): after bigjimmybot.ControlServer %v goroutines.", runtime.NumGoroutine())
}