返回 DeepSeek-Reasonix
creation.go
1 package workspacestate
2
3 import (
4 "context"
5 "errors"
6 "strings"
7 "time"
8 )
9
10 func (s *Store) BeginCreate(ctx context.Context, pending PendingCreate) error {
11 _, err := s.beginCreate(ctx, pending, "")
12 return err
13 }
14
15 func (s *Store) beginCreate(ctx context.Context, pending PendingCreate, root string) (Workspace, error) {
16 var workspace Workspace
17 pending.OperationID = strings.TrimSpace(pending.OperationID)
18 pending.WorkspaceID = strings.TrimSpace(pending.WorkspaceID)
19 pending.SessionID = strings.TrimSpace(pending.SessionID)
20 if pending.OperationID == "" || pending.WorkspaceID == "" || pending.SessionID == "" {
21 return workspace, errors.New("pending create requires operation, workspace, and session ids")
22 }
23 err := s.mutate(ctx, func(state *State) error {
24 if root != "" {
25 var err error
26 workspace, err = resolveCreationWorkspace(*state, pending.WorkspaceID, root, pending.SessionID)
27 if err != nil {
28 return err
29 }
30 pending.WorkspaceID = workspace.ID
31 }
32 if _, ok := state.Workspaces[pending.WorkspaceID]; !ok {
33 return ErrWorkspaceNotFound
34 }
35 if state.SessionStates[pending.SessionID].Lifecycle == Deleted {
36 return ErrMutationConflict
37 }
38 if current, ok := state.PendingCreates[pending.SessionID]; ok {
39 if current.OperationID == pending.OperationID && current.WorkspaceID == pending.WorkspaceID {
40 return nil
41 }
42 return ErrMutationConflict
43 }
44 if owner, ok := sessionOwner(*state, pending.SessionID); ok && owner != pending.WorkspaceID {
45 return ErrMutationConflict
46 }
47 if pending.CreatedAt.IsZero() {
48 pending.CreatedAt = time.Now().UTC()
49 }
50 state.PendingCreates[pending.SessionID] = pending
51 return nil
52 })
53 return workspace, err
54 }
55
56 func (s *Store) AttachSession(ctx context.Context, operationID, workspaceID, sessionID, beforeSessionID string) error {
57 return s.attachSession(ctx, operationID, workspaceID, sessionID, beforeSessionID, "", nil)
58 }
59
60 // AttachSessionFromSourceIfUnchanged publishes a derived child only while its
61 // resolved source is still active, in the same workspace, and at the same
62 // lifecycle generation.
63 func (s *Store) AttachSessionFromSourceIfUnchanged(
64 ctx context.Context,
65 operationID, workspaceID, sessionID, beforeSessionID, sourceSessionID string,
66 sourceGeneration uint64,
67 ) error {
68 return s.attachSession(ctx, operationID, workspaceID, sessionID, beforeSessionID, sourceSessionID, &sourceGeneration)
69 }
70
71 func (s *Store) attachSession(
72 ctx context.Context,
73 operationID, workspaceID, sessionID, beforeSessionID, sourceSessionID string,
74 sourceGeneration *uint64,
75 creationRoot ...string,
76 ) error {
77 operationID, workspaceID, sessionID = strings.TrimSpace(operationID), strings.TrimSpace(workspaceID), strings.TrimSpace(sessionID)
78 if workspaceID == "" || sessionID == "" {
79 return errors.New("attach requires workspace and session ids")
80 }
81 return s.mutate(ctx, func(state *State) error {
82 if len(creationRoot) > 0 {
83 workspace, err := resolveCreationWorkspace(*state, workspaceID, creationRoot[0], sessionID)
84 if err != nil {
85 return err
86 }
87 workspaceID = workspace.ID
88 }
89 if sourceGeneration != nil {
90 sourceSessionID = strings.TrimSpace(sourceSessionID)
91 sourceState := state.SessionStates[sourceSessionID]
92 sourceOwner, owned := sessionOwner(*state, sourceSessionID)
93 if sourceSessionID == "" || !owned || sourceOwner != workspaceID ||
94 sourceState.Lifecycle != Active || sourceState.Generation != *sourceGeneration {
95 return ErrMutationConflict
96 }
97 }
98 if state.SessionStates[sessionID].Lifecycle == Deleted {
99 return ErrMutationConflict
100 }
101 workspace, ok := state.Workspaces[workspaceID]
102 if !ok {
103 return ErrWorkspaceNotFound
104 }
105 if owner, owned := sessionOwner(*state, sessionID); owned {
106 if owner != workspaceID {
107 return ErrMutationConflict
108 }
109 delete(state.PendingCreates, sessionID)
110 return nil
111 }
112 if operationID != "" {
113 pending, ok := state.PendingCreates[sessionID]
114 if !ok || pending.OperationID != operationID || pending.WorkspaceID != workspaceID {
115 return ErrMutationConflict
116 }
117 }
118 workspace.SessionIDs = insertBefore(workspace.SessionIDs, sessionID, beforeSessionID)
119 if sourceSessionID == "" {
120 sourceSessionID = state.PendingCreates[sessionID].ParentSessionID
121 }
122 attachOrganizationSession(&workspace, sessionID, sourceSessionID)
123 mirrorOrganizationOrder(&workspace)
124 if pending, ok := state.PendingCreates[sessionID]; ok && pending.Presentation != nil {
125 state.Presentation[sessionID] = *pending.Presentation
126 }
127 workspace.UpdatedAt = time.Now().UTC()
128 state.Workspaces[workspaceID] = workspace
129 delete(state.PendingCreates, sessionID)
130 return nil
131 })
132 }
133
133 lines GO