func (k *Klient) send(queryString, method string, req, resp interface{}) (string, error) { queryString, err := utils.QueryString(queryString) if err != nil { return "", err } k.Log.Debug("calling %q method on %q with %+v", method, queryString, req) kref, err := klient.ConnectTimeout(k.Kite, queryString, k.dialTimeout()) if err != nil { k.Log.Debug("connecting to %q klient failed: %s", queryString, err) return "", err } defer kref.Close() r, err := kref.Client.TellWithTimeout(method, k.timeout(), req) if err != nil { k.Log.Debug("sending request to %q klient failed: %s", queryString, err) return "", err } if err := r.Unmarshal(resp); err != nil { return "", errors.New("reading response from klient failed: " + err.Error()) } k.Log.Debug("received %+v response from %q (%q)", resp, method, queryString) return kref.URL(), nil }
func (k *Klient) cmd(queryString, method, boxPath string) error { queryString, err := utils.QueryString(queryString) if err != nil { return err } k.Log.Debug("calling %q command on %q with %q", method, queryString, boxPath) kref, err := klient.ConnectTimeout(k.Kite, queryString, k.dialTimeout()) if err != nil { k.Log.Debug("connecting to %q klient failed: %s", queryString, err) return err } done := make(chan error, 1) success := dnode.Callback(func(*dnode.Partial) { done <- nil }) failure := dnode.Callback(func(r *dnode.Partial) { msg, err := r.One().String() if err != nil { err = errors.New("unknown failure") } else { err = errors.New(msg) } done <- err }) lost := make(chan struct{}) beat := make(chan struct{}) stop := make(chan struct{}) defer close(stop) go func() { // Heartbeat timer is initially stopped since at this // point we do not know whether klient supports heartbeats. // On first heartbeat we activate the timer and set the ch. var ( t *time.Timer ch <-chan time.Time ) for { select { case <-stop: return case <-ch: lost <- struct{}{} case <-beat: if t == nil { t = time.NewTimer(defaultDialTimeout) ch = t.C defer t.Stop() } t.Reset(defaultDialTimeout) } } }() heartbeat := dnode.Callback(func(r *dnode.Partial) { beat <- struct{}{} }) req := &Command{ FilePath: boxPath, Success: success, Failure: failure, Heartbeat: heartbeat, } if k.Debug { log := k.Log.New(method) req.Output = dnode.Callback(func(r *dnode.Partial) { log.Debug("%s", r.One().MustString()) }) } if _, err = kref.Client.TellWithTimeout(method, k.timeout(), req); err != nil { return errors.New("sending request to klient failed: " + err.Error()) } select { case err := <-done: return err case <-time.After(k.timeout()): return fmt.Errorf("timed out calling %q on %q", method, queryString) case <-lost: return errors.New("connection to your KD Daemon was lost due to inactivity") } }
// RemoveUsersFromMachine removes the collaboraters from the host machine func (c *Controller) RemoveUsersFromMachine(ping *models.Ping, toBeRemovedUsers []bson.ObjectId) error { // if channel id is nil, there is nothing to do if ping.ChannelId == 0 { return nil } ws, err := modelhelper.GetWorkspaceByChannelId(strconv.FormatInt(ping.ChannelId, 10)) if err != nil { return filterErr(err) } m, err := modelhelper.GetMachineByUid(ws.MachineUID) if err != nil { return filterErr(err) } // Get the klient. klientRef, err := klient.ConnectTimeout(c.kite, m.QueryString, time.Second*10) if err != nil { if err == klient.ErrDialingFailed || err == kite.ErrNoKitesAvailable { c.log.Error( "[%s] Klient is not registered to Kontrol. Err: %s", m.QueryString, err, ) return nil // if the machine is not open, we cant do anything } return err } defer klientRef.Close() type args struct { Username string // we are not gonna use this propery here, just for reference // Permanent bool } var iterErr error for _, toBeDeletedUser := range toBeRemovedUsers { // fetch user for its username u, err := modelhelper.GetUserById(toBeDeletedUser.Hex()) if err != nil { c.log.Error("couldnt get user", err.Error()) // if we cant find the regarding user, do not do anything if err == mgo.ErrNotFound { continue } iterErr = err continue // do not stop iterating, unshare from others } param := args{ Username: u.Name, } _, err = klientRef.Client.Tell("klient.unshare", param) if err != nil { c.log.Error("couldnt unshare %+v", err.Error()) // those are so error prone, force klient side not to change the API // or make them exported to some other package? if strings.Contains(err.Error(), "user is permanent") { continue } if strings.Contains(err.Error(), "user is not in the shared list") { continue } if strings.Contains(err.Error(), "User not found") { continue } iterErr = err continue // do not stop iterating, unshare from others } } res, err := klientRef.Client.Tell("klient.shared", nil) if err == nil { c.log.Info("other users in the machine: %+v", res.MustString()) } // iterErr will be nil if we dont encounter to any error in iter return iterErr }