// Starts listening for commands through the given app's connection. // Since this is a blocking function, it should likely be called in // a goroutine. // At the end of the function, closes the application's network resources. func ListenForCommands(a *app.App) { defer closeApp(a) // loop forever consuming messages for { // get the next command strategy, err := getCommand(a) if err != nil { id := "NO_ID_FOUND" if a.Manifest != nil { id = a.Manifest.InstanceId } logging.Error("Application %s encountered fatal error: %s", id, err.Error()) return } // do the command if strategy.GetVerb() == "APP_MANIFEST" { if !strategy.Execute() { logging.Error("Application's manifest did not parse correctly") return } } else { // HACK to get around golang compiler error // originally: // go strategy.Execute() // message: // "go requires function call not conversion" go performStrategy(strategy) } } }
func (c *commandStrategy) Execute() bool { var err error ret := true switch c.verb { case "APP_MANIFEST": ret = c.appManifest() case "APP_UP", "APP_DOWN", "APP_IN_USE": err = c.statusChange() case "MSG_QUERY": err = c.msgQuery() case "MSG_BROADCAST": err = c.msgBroadcast() case "MSG_QUERY_SUCCESS": err = c.msgQuerySuccess() case "MSG_QUERY_FAIL": err = c.msgQueryFail() default: err = fmt.Errorf("No matching verb found for %s", c.verb) } if err != nil { id := "NO_ID_FOUND" if c.app.Manifest != nil { id = c.app.Manifest.InstanceId } logging.Error("Application %s had command error %s", id, err.Error()) b, _ := json.Marshal(c.body) return newFailedCommandStrategy(c.app, string(b), err.Error()).Execute() } return ret }
// Parses a command given the command's message string // (verb and body, no message length) func ParseCommand(a *app.App, message string) (CommandStrategy, bool) { id := "NO_ID_FOUND" if a.Manifest != nil { id = a.Manifest.InstanceId } logging.Debug("Parsing from app %s: \n%s", id, message) ret, err := internalParseCommand(a, message) if err != nil { logging.Error("Parse failed from app %s: %s", id, err.Error()) return newFailedCommandStrategy(a, message, err.Error()), false } return ret, true }
// construct the app based on its manifest func (c *commandStrategy) appManifest() bool { c.app.RWMutex.Lock() defer c.app.RWMutex.Unlock() logging.Debug("Parsing application's manifest") man, err := decodeManifest(c.body) if err != nil { logging.Error("App's manifest is invalid: %s", err) sendManifestFail(c.app, err.Error()) return false } if _, exists := registry.GetInstance(man.InstanceId); exists { logging.Error("App's instance id is already taken: %s", man.InstanceId) sendManifestFail(c.app, fmt.Sprintf("instanceId %s is in use", man.InstanceId)) return false } c.app.Status = app.STATUS_DOWN c.app.Manifest = man registry.Register(c.app) sendManifestOkAndDependencies(c.app) logging.Info("App '%s' now connected with manifest parsed", c.app.Manifest.InstanceId) return true }