func serveClient(client *clients.Client) { conn := client.Conn rr := redis.NewRespReader(conn) outer: for { var command string var args []string m := rr.Read() if m.IsType(redis.IOErr) { log.L.Debug(client.Sprintf("client connection error %q", m.Err)) if len(client.Queues) > 0 { consumers.UpdateQueues(client, []string{}) } client.Close() return } parts, err := m.Array() if err != nil { log.L.Debug(client.Sprintf("error parsing to array: %q", err)) continue outer } for i := range parts { val, err := parts[i].Str() if err != nil { log.L.Debug(client.Sprintf("invalid command part %#v: %s", parts[i], err)) invalidCmdResp.WriteTo(conn) continue outer } if i == 0 { command = val } else { args = append(args, val) } } log.L.Debug(client.Sprintf("%s %#v", command, args)) commands.Dispatch(client, command, args) } }
// Dispatch takes in a client whose command has already been read off the // socket, a list of arguments from that command (not including the command name // itself), and handles that command func Dispatch(client *clients.Client, cmd string, args []string) { cmdInfo, ok := commandMap[strings.ToUpper(cmd)] if !ok { writeErrf(client.Conn, "ERR unknown command %q", cmd) return } if len(args) < cmdInfo.minArgs { writeErrf(client.Conn, "ERR missing args") return } ret, err := cmdInfo.f(client, args) if err != nil { writeErrf(client.Conn, "ERR unexpected server-side error") log.L.Print(client.Sprintf("command %s %#v err: %s", cmd, args, err)) return } redis.NewResp(ret).WriteTo(client.Conn) }
func qregister(client *clients.Client, args []string) (interface{}, error) { err := consumers.UpdateQueues(client, args) if err != nil { return nil, fmt.Errorf("QREGISTER UpdateQueues: %s", err) } client.Queues = args return okSS, nil }
func qnotify(client *clients.Client, args []string) (interface{}, error) { timeout, err := parseInt(args[0], "timeout") if err != nil { return err, nil } // ensure the NotifyCh is empty before waiting queueName := "" client.DrainNotifyCh() // check to see if we have any events in the registered queues. We check the // list in a randomized order since very active queues in the list may not // ever let us check after them in the list, abandoning the rest of the list queueNames := client.Queues for _, i := range rand.Perm(len(queueNames)) { unclaimedKey := db.UnclaimedKey(queueNames[i]) var unclaimedCount int unclaimedCount, err = db.Inst.Cmd("LLEN", unclaimedKey).Int() if err != nil { return nil, fmt.Errorf("QNOTIFY LLEN unclaimed): %s", err) } if unclaimedCount > 0 { queueName = queueNames[i] break } } if queueName == "" { select { case <-time.After(time.Duration(timeout) * time.Second): case queueName = <-client.NotifyCh: } } if queueName != "" { return queueName, nil } return nil, nil }