| 1 | package console |
| 2 | |
| 3 | import "context" |
| 4 | |
| 5 | // createClaimAppRow inserts a new app's SQL row through insert. Flag-off it is |
| 6 | // insert on the store, exactly as before. |
| 7 | // |
| 8 | // Enabled, the armed gate refuses an apps row nobody holds a permit for, and a |
| 9 | // permit is derived from canonical admission, so the order is reversed: the |
| 10 | // bucket CAS reserves the canonical identity first (EnrollNewApp is idempotent |
| 11 | // for an open admission, so a racer in this or another console converges on |
| 12 | // the same app_id), then one app mutation of that identity inserts the row and |
| 13 | // binds app_id in the same permitted view. A refused enrollment (a foreign |
| 14 | // operation, a name that is not free) leaves no SQL row. A lost SQL race |
| 15 | // reports created false and binds nothing; the open admission is the winner's. |
| 16 | func (s *Server) createClaimAppRow(ctx context.Context, acct *Account, app string, insert func(*Store) (bool, error)) (bool, error) { |
| 17 | if !s.cfg.HostClaim { |
| 18 | return insert(s.store) |
| 19 | } |
| 20 | w, err := s.claimControl() |
| 21 | if err != nil { |
| 22 | return false, err |
| 23 | } |
| 24 | appID, err := w.EnrollNewApp(ctx, acct.Sqid, app) |
| 25 | if err != nil { |
| 26 | return false, err |
| 27 | } |
| 28 | ctx, err = s.claimEnrollmentContext(ctx, acct, app, appID) |
| 29 | if err != nil { |
| 30 | return false, err |
| 31 | } |
| 32 | created := false |
| 33 | err = s.store.withAutoAppSQL(ctx, acct.ID, app, "sql.CreateApp", func(st *Store) error { |
| 34 | var err error |
| 35 | if created, err = insert(st); err != nil || !created { |
| 36 | return err |
| 37 | } |
| 38 | return st.BindClaimAppIdentity(acct.ID, app, appID) |
| 39 | }) |
| 40 | if err != nil { |
| 41 | return false, err |
| 42 | } |
| 43 | return created, nil |
| 44 | } |
| 45 | |