Skip to content

Commit d73e701

Browse files
committed
File variable type
1 parent cd2ba0f commit d73e701

File tree

8 files changed

+206
-37
lines changed

8 files changed

+206
-37
lines changed

generator/examples/bella.json

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

generator/variable/file.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package variable
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/EliCDavis/jbtf"
7+
"github.com/EliCDavis/polyform/generator/schema"
8+
"github.com/EliCDavis/polyform/nodes"
9+
)
10+
11+
type FileVariable struct {
12+
value []byte
13+
version int
14+
info Info
15+
}
16+
17+
func (tv *FileVariable) SetValue(v []byte) {
18+
tv.value = v
19+
tv.version++
20+
}
21+
22+
func (tv *FileVariable) GetValue() []byte {
23+
return tv.value
24+
}
25+
26+
func (tv *FileVariable) Version() int {
27+
return tv.version
28+
}
29+
30+
func (tv *FileVariable) Info() Info {
31+
return tv.info
32+
}
33+
34+
func (tv *FileVariable) setInfo(i Info) error {
35+
if tv.info != nil {
36+
return fmt.Errorf("already assigned info")
37+
}
38+
tv.info = i
39+
return nil
40+
}
41+
42+
func (tv *FileVariable) currentValue() any {
43+
return tv.value
44+
}
45+
46+
func (tv *FileVariable) currentVersion() int {
47+
return tv.version
48+
}
49+
50+
func (tv *FileVariable) ApplyMessage(msg []byte) (bool, error) {
51+
52+
// if pn.appliedProfile != nil && val == *pn.appliedProfile {
53+
// return false, nil
54+
// }
55+
56+
tv.version++
57+
tv.value = msg
58+
return true, nil
59+
}
60+
61+
func (tv FileVariable) ToMessage() []byte {
62+
return tv.value
63+
}
64+
65+
func (tv *FileVariable) NodeReference() nodes.Node {
66+
return &VariableReferenceNode[[]byte]{
67+
variable: tv,
68+
}
69+
}
70+
71+
// func (tv FileVariable) MarshalJSON() ([]byte, error) {
72+
// var t T
73+
// return json.Marshal(typedVariableSchema[T]{
74+
// variableSchemaBase: variableSchemaBase{
75+
// Type: refutil.GetTypeName(t),
76+
// },
77+
// Value: tv.value,
78+
// })
79+
// }
80+
81+
type fileDetails struct {
82+
Size int `json:"size"`
83+
}
84+
85+
func (tv FileVariable) runtimeSchema() schema.RuntimeVariable {
86+
return schema.RuntimeVariable{
87+
Description: tv.info.Description(),
88+
Type: "file", // refutil.GetTypeName(tv.value),
89+
Value: fileDetails{
90+
Size: len(tv.value),
91+
},
92+
}
93+
}
94+
95+
type fileNodeGraphSchema struct {
96+
Type string `json:"type"`
97+
Value *jbtf.Bytes
98+
}
99+
100+
func (tv FileVariable) toPersistantJSON(encoder *jbtf.Encoder) ([]byte, error) {
101+
schema := fileNodeGraphSchema{
102+
Type: "file",
103+
}
104+
105+
if tv.value != nil {
106+
schema.Value = &jbtf.Bytes{
107+
Data: tv.value,
108+
}
109+
}
110+
111+
return encoder.Marshal(schema)
112+
}
113+
114+
func (tv *FileVariable) fromPersistantJSON(decoder jbtf.Decoder, body []byte) error {
115+
gn, err := jbtf.Decode[fileNodeGraphSchema](decoder, body)
116+
if err != nil {
117+
return err
118+
}
119+
if gn.Value != nil {
120+
tv.value = gn.Value.Data
121+
}
122+
return nil
123+
}

generator/variable/serialization.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ func deserialiseImageVariable(msg []byte, decoder jbtf.Decoder) (Variable, error
5353
return iv, iv.fromPersistantJSON(decoder, msg)
5454
}
5555

56+
func deserialiseFileVariable(msg []byte, decoder jbtf.Decoder) (Variable, error) {
57+
iv := &FileVariable{}
58+
return iv, iv.fromPersistantJSON(decoder, msg)
59+
}
60+
5661
type variableSchemaBase struct {
5762
Type string `json:"type"`
5863
}
@@ -101,6 +106,9 @@ func DeserializePersistantVariableJSON(msg []byte, decoder jbtf.Decoder) (Variab
101106
case "image.image":
102107
return deserialiseImageVariable(msg, decoder)
103108

109+
case "file":
110+
return deserialiseFileVariable(msg, decoder)
111+
104112
default:
105113
return nil, fmt.Errorf("unrecognized variable type: %q", vsb.Type)
106114
}
@@ -144,6 +152,9 @@ func CreateVariable(variableType string) (Variable, error) {
144152
case "image.image":
145153
return &ImageVariable{}, nil
146154

155+
case "file":
156+
return &FileVariable{}, nil
157+
147158
default:
148159
return nil, fmt.Errorf("unrecognized variable type: %q", variableType)
149160
}

generator/variable/system.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ func (s *system) Move(oldName, newName string) error {
133133
return fmt.Errorf("new path can not be empty")
134134
}
135135

136+
if oldName == clean {
137+
return nil
138+
}
139+
136140
s.mutex.Lock()
137141
defer s.mutex.Unlock()
138142

website/popups/edit_variable.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export class EditVariablePopup {
9191

9292
saveClicked(): void {
9393
this.closePopup();
94-
if (this.name.value === this.variableKey) {
94+
if (this.name.value === this.variableKey && this.description.value === this.variable.description) {
9595
return;
9696
}
9797
this.updateVariable({

website/popups/variable_type_dropdown.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export function VariableTypeDropdown(change$: BehaviorSubject<string>): ElementC
1919
{ tag: "option", value: VariableType.Color, text: "Color" },
2020
{ tag: "option", value: VariableType.Float3Array, text: "Float3 Array" },
2121
{ tag: "option", value: VariableType.Image, text: "Image" },
22+
{ tag: "option", value: VariableType.File, text: "File" },
2223
]
2324
};
2425
}

website/variable_manager.ts

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,39 @@ function postBinaryEmptyResponse(theUrl: string, body: any, callback): void {
5959
xmlHttp.send(body);
6060
}
6161

62+
function uploadBinaryAsVariableValue(variableKey: string): void {
63+
const input = document.createElement('input');
64+
input.type = 'file';
65+
66+
input.onchange = e => {
67+
const file = (e.target as HTMLInputElement).files[0];
68+
69+
const reader = new FileReader();
70+
reader.readAsArrayBuffer(file);
71+
72+
reader.onload = readerEvent => {
73+
const content = readerEvent.target.result as string; // this is the content!
74+
postBinaryEmptyResponse("./variable/value/" + variableKey, content, () => {
75+
location.reload();
76+
})
77+
}
78+
}
79+
80+
input.click();
81+
}
82+
83+
function formatFileSize(bytes: number): string {
84+
if (bytes === 0) return '0 B';
85+
86+
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
87+
const k = 1024;
88+
const i = Math.floor(Math.log(bytes) / Math.log(k));
89+
const size = bytes / Math.pow(k, i);
90+
91+
// Show up to one decimal if needed
92+
return `${size.toFixed(size < 10 && i > 0 ? 1 : 0)} ${units[i]}`;
93+
}
94+
6295
export class VariableManager {
6396

6497
variableListView: Element;
@@ -118,19 +151,10 @@ export class VariableManager {
118151
}
119152

120153
newImageVariable(key: string, variable: Variable): ElementConfig {
121-
const variableTopic = new Subject<string>();
122-
123-
// variableTopic.pipe(
124-
// map(mapper),
125-
// mergeMap((val) => this.setVariableValue(key, val))
126-
// ).subscribe((resp: Response) => {
127-
// console.log(resp);
128-
// })
129-
130154
return {
131155
style: {
132156
display: "flex",
133-
flexDirection:"column",
157+
flexDirection: "column",
134158
gap: "8px"
135159
},
136160
children: [
@@ -145,33 +169,34 @@ export class VariableManager {
145169
tag: "button",
146170
text: "Set Image",
147171
onclick: () => {
148-
const input = document.createElement('input');
149-
input.type = 'file';
150-
151-
input.onchange = e => {
152-
const file = (e.target as HTMLInputElement).files[0];
153-
154-
const reader = new FileReader();
155-
reader.readAsArrayBuffer(file);
156-
157-
reader.onload = readerEvent => {
158-
const content = readerEvent.target.result as string; // this is the content!
159-
postBinaryEmptyResponse("./variable/value/" + key, content, () => {
160-
location.reload();
161-
})
162-
}
163-
}
172+
uploadBinaryAsVariableValue(key);
173+
}
174+
}
175+
]
176+
};
177+
}
164178

165-
input.click();
179+
newFileVariable(key: string, variable: Variable): ElementConfig {
180+
return {
181+
style: {
182+
display: "flex",
183+
flexDirection: "column",
184+
gap: "8px"
185+
},
186+
children: [
187+
{
188+
text: formatFileSize(variable.value.size),
189+
style: {
190+
maxWidth: "100%"
191+
}
192+
},
193+
{
194+
tag: "button",
195+
text: "Set File",
196+
onclick: () => {
197+
uploadBinaryAsVariableValue(key);
166198
}
167199
}
168-
// {
169-
// tag: "input",
170-
// // change$: variableTopic,
171-
// value: `${variable.value}`,
172-
// size: 1,
173-
// classList: ['variable-number-input'],
174-
// }
175200
]
176201
};
177202
}
@@ -412,6 +437,10 @@ export class VariableManager {
412437
console.log(variable);
413438
break;
414439

440+
case VariableType.File:
441+
input = this.newFileVariable(key, variable)
442+
break;
443+
415444
default:
416445
throw new Error("unimplemented variable type: " + variable.type);
417446
}

website/variable_type.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ export enum VariableType {
1010
Color = "coloring.WebColor",
1111
Bool = "bool",
1212
AABB = "geometry.AABB",
13-
Image = "image.Image"
13+
Image = "image.Image",
14+
File = "file"
1415
}

0 commit comments

Comments
 (0)