Skip to content

Commit ec194fd

Browse files
authored
Profile: Create/Delete/Overwrite/Rename. Fog updates. (#102)
1 parent 6ecf1aa commit ec194fd

32 files changed

+729
-70
lines changed

cmd/polyform/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ import (
4747
func main() {
4848
app := generator.App{
4949
Name: "Polyform",
50-
Version: "0.23.2",
51-
Description: "Immutable mesh processing program",
50+
Version: "",
51+
Description: "Immutable mesh processing pipelines",
5252
Authors: []schema.Author{
5353
{
5454
Name: "Eli C Davis",

generator/app_server.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,13 @@ func (as *AppServer) Handler(indexFile string) (*http.ServeMux, error) {
148148
mux.Handle("/parameter/value/", parameterValueEndpoint(as.app.graphInstance, graphSaver))
149149
mux.Handle("/parameter/name/", parameterNameEndpoint(as.app.graphInstance, graphSaver))
150150
mux.Handle("/parameter/description/", parameterDescriptionEndpoint(as.app.graphInstance, graphSaver))
151+
152+
mux.Handle("/profile", profileEndpoint(as.app.graphInstance, graphSaver))
153+
mux.Handle("/profile/apply", applyProfileEndpoint(as.app.graphInstance, graphSaver))
154+
mux.Handle("/profile/rename", renameProfileEndpoint(as.app.graphInstance, graphSaver))
155+
mux.Handle("/profile/overwrite", overwriteProfileEndpoint(as.app.graphInstance, graphSaver))
156+
mux.Handle("/profiles", profilesEndpoint(as.app.graphInstance))
157+
151158
mux.Handle("/new-graph", newGraphEndpoint(as.app, as))
152159
mux.Handle("/load-example", exampleGraphEndpoint(as.app, as))
153160
mux.Handle("/graph", graphEndpoint(as.app, as))

generator/app_server_profile.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package generator
2+
3+
import (
4+
"errors"
5+
"net/http"
6+
"strings"
7+
8+
"github.com/EliCDavis/polyform/generator/endpoint"
9+
"github.com/EliCDavis/polyform/generator/graph"
10+
)
11+
12+
func profileEndpoint(graphInstance *graph.Instance, saver *GraphSaver) endpoint.Handler {
13+
type ProfileRequest struct {
14+
Name string `json:"name"`
15+
}
16+
17+
return endpoint.Handler{
18+
Methods: map[string]endpoint.Method{
19+
20+
http.MethodPost: endpoint.JsonBodyMethod(func(request endpoint.Request[ProfileRequest]) error {
21+
cleanName := strings.TrimSpace(request.Body.Name)
22+
23+
if cleanName == "" {
24+
return errors.New("profile name can not be empty")
25+
}
26+
27+
graphInstance.SaveProfile(cleanName)
28+
29+
saver.Save()
30+
return nil
31+
}),
32+
33+
http.MethodDelete: endpoint.JsonBodyMethod(func(request endpoint.Request[ProfileRequest]) error {
34+
err := graphInstance.DeleteProfile(request.Body.Name)
35+
if err != nil {
36+
return err
37+
}
38+
saver.Save()
39+
40+
return nil
41+
}),
42+
},
43+
}
44+
}
45+
46+
func profilesEndpoint(graphInstance *graph.Instance) endpoint.Handler {
47+
return endpoint.Handler{
48+
Methods: map[string]endpoint.Method{
49+
http.MethodGet: endpoint.JsonResponseMethod(func(r *http.Request) ([]string, error) {
50+
return graphInstance.Profiles(), nil
51+
}),
52+
},
53+
}
54+
}
55+
56+
func applyProfileEndpoint(graphInstance *graph.Instance, saver *GraphSaver) endpoint.Handler {
57+
type ApplyProfileRequest struct {
58+
Name string `json:"name"`
59+
}
60+
61+
return endpoint.Handler{
62+
Methods: map[string]endpoint.Method{
63+
http.MethodPost: endpoint.JsonBodyMethod(func(request endpoint.Request[ApplyProfileRequest]) error {
64+
err := graphInstance.LoadProfile(request.Body.Name)
65+
if err != nil {
66+
return err
67+
}
68+
saver.Save()
69+
return nil
70+
}),
71+
},
72+
}
73+
}
74+
75+
func renameProfileEndpoint(graphInstance *graph.Instance, saver *GraphSaver) endpoint.Handler {
76+
type RenameProfileRequest struct {
77+
Original string `json:"original"`
78+
New string `json:"new"`
79+
}
80+
81+
return endpoint.Handler{
82+
Methods: map[string]endpoint.Method{
83+
http.MethodPost: endpoint.JsonBodyMethod(func(request endpoint.Request[RenameProfileRequest]) error {
84+
err := graphInstance.RenameProfile(request.Body.Original, request.Body.New)
85+
if err != nil {
86+
return err
87+
}
88+
saver.Save()
89+
return nil
90+
}),
91+
},
92+
}
93+
}
94+
95+
func overwriteProfileEndpoint(graphInstance *graph.Instance, saver *GraphSaver) endpoint.Handler {
96+
type OverwriteProfileRequest struct {
97+
Name string `json:"name"`
98+
}
99+
100+
return endpoint.Handler{
101+
Methods: map[string]endpoint.Method{
102+
http.MethodPost: endpoint.JsonBodyMethod(func(request endpoint.Request[OverwriteProfileRequest]) error {
103+
graphInstance.SaveProfile(request.Body.Name)
104+
saver.Save()
105+
return nil
106+
}),
107+
},
108+
}
109+
}

generator/endpoint/json.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,16 @@ func JsonMethod[Body any, Response any](handler func(request Request[Body]) (Res
6868
Handler: handler,
6969
}
7070
}
71+
72+
func JsonBodyMethod[Body any](handler func(request Request[Body]) error) BodyMethod[Body] {
73+
return BodyMethod[Body]{
74+
Request: JsonRequestReader[Body]{},
75+
Handler: handler,
76+
}
77+
}
78+
79+
func JsonResponseMethod[Response any](handler func(r *http.Request) (Response, error)) ResponseMethod[Response] {
80+
return ResponseMethod[Response]{
81+
ResponseWriter: JsonResponseWriter[Response]{},
82+
}
83+
}

generator/examples/eyeball.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

generator/examples/tower.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

generator/graph/instance.go

Lines changed: 106 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ type Instance struct {
2727
namedManifests *namedOutputManager[manifest.Manifest]
2828
variables variable.System
2929

30+
profiles map[string]variable.Profile
31+
3032
// TODO: Make this a lock across the entire instance
31-
producerLock gsync.Mutex
33+
lock gsync.RWMutex
3234
}
3335

3436
func New(typeFactory *refutil.TypeFactory) *Instance {
@@ -127,8 +129,8 @@ func (i *Instance) SetVariableDescription(variablePath, description string) erro
127129
}
128130

129131
func (i *Instance) UpdateVariable(variablePath string, data []byte) (bool, error) {
130-
i.producerLock.Lock()
131-
defer i.producerLock.Unlock()
132+
i.lock.Lock()
133+
defer i.lock.Unlock()
132134

133135
variable, err := i.variables.Variable(variablePath)
134136
if err != nil {
@@ -141,8 +143,8 @@ func (i *Instance) UpdateVariable(variablePath string, data []byte) (bool, error
141143
}
142144

143145
func (i *Instance) VariableData(variablePath string) ([]byte, error) {
144-
i.producerLock.Lock()
145-
defer i.producerLock.Unlock()
146+
i.lock.Lock()
147+
defer i.lock.Unlock()
146148

147149
variable, err := i.variables.Variable(variablePath)
148150
if err != nil {
@@ -153,6 +155,76 @@ func (i *Instance) VariableData(variablePath string) ([]byte, error) {
153155

154156
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
155157

158+
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
159+
// Profiles
160+
// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
161+
162+
func (i *Instance) SaveProfile(profileName string) {
163+
i.lock.Lock()
164+
defer i.lock.Unlock()
165+
166+
i.profiles[profileName] = i.variables.GetProfile()
167+
}
168+
169+
func (i *Instance) LoadProfile(profileName string) error {
170+
i.lock.Lock()
171+
defer i.lock.Unlock()
172+
173+
if profile, ok := i.profiles[profileName]; ok {
174+
return i.variables.ApplyProfile(profile)
175+
}
176+
177+
return fmt.Errorf("no profile exists with name %q", profileName)
178+
}
179+
180+
func (i *Instance) RenameProfile(profile, newName string) error {
181+
i.lock.Lock()
182+
defer i.lock.Unlock()
183+
184+
if _, ok := i.profiles[profile]; !ok {
185+
return fmt.Errorf("profile %q does not exist", profile)
186+
}
187+
188+
if _, ok := i.profiles[newName]; ok {
189+
return fmt.Errorf("profile %q already exists", profile)
190+
}
191+
192+
i.profiles[newName] = i.profiles[profile]
193+
194+
delete(i.profiles, profile)
195+
196+
return nil
197+
}
198+
199+
func (i *Instance) DeleteProfile(profileName string) error {
200+
i.lock.Lock()
201+
defer i.lock.Unlock()
202+
203+
if _, ok := i.profiles[profileName]; !ok {
204+
return fmt.Errorf("graph contains no profile named %q", profileName)
205+
}
206+
207+
delete(i.profiles, profileName)
208+
return nil
209+
}
210+
211+
func (i *Instance) Profiles() []string {
212+
i.lock.RLock()
213+
defer i.lock.RUnlock()
214+
215+
profiles := make([]string, 0, len(i.profiles))
216+
217+
for profile := range i.profiles {
218+
profiles = append(profiles, profile)
219+
}
220+
221+
sort.Strings(profiles)
222+
223+
return profiles
224+
}
225+
226+
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
227+
156228
func (i *Instance) IsPortNamed(node nodes.Node, portName string) (string, bool) {
157229
return i.namedManifests.IsPortNamed(node, portName)
158230
}
@@ -316,6 +388,7 @@ func (i *Instance) Reset() {
316388
i.namedManifests = &namedOutputManager[manifest.Manifest]{
317389
namedPorts: make(map[string]namedOutputEntry[manifest.Manifest]),
318390
}
391+
i.profiles = make(map[string]variable.Profile)
319392
}
320393

321394
type sortedReference struct {
@@ -397,6 +470,10 @@ func (i *Instance) ApplyAppSchema(jsonPayload []byte) error {
397470
return err
398471
}
399472

473+
for profile, data := range appSchema.Profiles {
474+
i.profiles[profile] = data.Data
475+
}
476+
400477
createdNodes := make(map[string]nodes.Node)
401478

402479
// Create the Nodes
@@ -506,6 +583,9 @@ func (i *Instance) ApplyAppSchema(jsonPayload []byte) error {
506583
}
507584

508585
func (i *Instance) Schema() schema.GraphInstance {
586+
i.lock.RLock()
587+
defer i.lock.RUnlock()
588+
509589
var noteMetadata map[string]any
510590
if notes := i.metadata.Get("notes"); notes != nil {
511591
casted, ok := notes.(map[string]any)
@@ -523,8 +603,14 @@ func (i *Instance) Schema() schema.GraphInstance {
523603
Producers: make(map[string]schema.Producer),
524604
Notes: noteMetadata,
525605
Variables: variableSchema,
606+
Profiles: make([]string, 0, len(i.profiles)),
526607
}
527608

609+
for profile := range i.profiles {
610+
appSchema.Profiles = append(appSchema.Profiles, profile)
611+
}
612+
sort.Strings(appSchema.Profiles)
613+
528614
appNodeSchema := make(map[string]schema.NodeInstance)
529615

530616
for node := range i.nodeIDs {
@@ -585,6 +671,15 @@ func (i *Instance) EncodeToAppSchema(appSchema *schema.App, encoder *jbtf.Encode
585671
nodeInstances[id] = nodeSchema
586672
}
587673

674+
if appSchema.Profiles == nil {
675+
appSchema.Profiles = make(map[string]schema.AppProfile)
676+
}
677+
for name, data := range i.profiles {
678+
appSchema.Profiles[name] = schema.AppProfile{
679+
Data: data,
680+
}
681+
}
682+
588683
if appSchema.Producers == nil {
589684
appSchema.Producers = make(map[string]schema.Producer)
590685
}
@@ -803,17 +898,17 @@ func (i *Instance) Parameter(nodeId string) Parameter {
803898
}
804899

805900
func (i *Instance) UpdateParameter(nodeId string, data []byte) (bool, error) {
806-
i.producerLock.Lock()
807-
defer i.producerLock.Unlock()
901+
i.lock.Lock()
902+
defer i.lock.Unlock()
808903

809904
r, err := i.Parameter(nodeId).ApplyMessage(data)
810905
i.incModelVersion()
811906
return r, err
812907
}
813908

814909
func (i *Instance) ParameterData(nodeId string) []byte {
815-
i.producerLock.Lock()
816-
defer i.producerLock.Unlock()
910+
i.lock.Lock()
911+
defer i.lock.Unlock()
817912
return i.Parameter(nodeId).ToMessage()
818913
}
819914

@@ -954,8 +1049,8 @@ func (i *Instance) Manifest(producerName string) manifest.Manifest {
9541049
panic(fmt.Errorf("no producer registered for: %s", producerName))
9551050
}
9561051

957-
i.producerLock.Lock()
958-
defer i.producerLock.Unlock()
1052+
i.lock.Lock()
1053+
defer i.lock.Unlock()
9591054

9601055
return producer.port.Value()
9611056
}

0 commit comments

Comments
 (0)