@@ -4,12 +4,10 @@ import { Constants } from "../constants";
4
4
import { EmulatorInfo , EmulatorInstance , Emulators } from "../types" ;
5
5
import { createApp } from "./server" ;
6
6
import { StorageLayer } from "./files" ;
7
- import * as chokidar from "chokidar" ;
8
7
import { EmulatorLogger } from "../emulatorLogger" ;
9
- import * as fs from "fs " ;
8
+ import { StorageRulesManager } from "./rules/manager " ;
10
9
import { StorageRulesetInstance , StorageRulesRuntime , StorageRulesIssues } from "./rules/runtime" ;
11
- import { Source } from "./rules/types" ;
12
- import { FirebaseError } from "../../error" ;
10
+ import { SourceFile } from "./rules/types" ;
13
11
import express = require( "express" ) ;
14
12
import { getRulesValidator } from "./rules/utils" ;
15
13
import { Persistence } from "./persistence" ;
@@ -19,25 +17,24 @@ export interface StorageEmulatorArgs {
19
17
projectId : string ;
20
18
port ?: number ;
21
19
host ?: string ;
22
- rules : Source | string ;
20
+ rules : SourceFile | string ;
23
21
auto_download ?: boolean ;
24
22
}
25
23
26
24
export class StorageEmulator implements EmulatorInstance {
27
25
private destroyServer ?: ( ) => Promise < void > ;
28
26
private _app ?: express . Express ;
29
- private _rulesWatcher ?: chokidar . FSWatcher ;
30
- private _rules ?: StorageRulesetInstance ;
31
- private _rulesetSource ?: Source ;
32
27
33
28
private _logger = EmulatorLogger . forEmulator ( Emulators . STORAGE ) ;
34
29
private _rulesRuntime : StorageRulesRuntime ;
30
+ private _rulesManager : StorageRulesManager ;
35
31
private _persistence : Persistence ;
36
32
private _storageLayer : StorageLayer ;
37
33
private _uploadService : UploadService ;
38
34
39
35
constructor ( private args : StorageEmulatorArgs ) {
40
36
this . _rulesRuntime = new StorageRulesRuntime ( ) ;
37
+ this . _rulesManager = new StorageRulesManager ( this . _rulesRuntime ) ;
41
38
this . _persistence = new Persistence ( this . getPersistenceTmpDir ( ) ) ;
42
39
this . _storageLayer = new StorageLayer (
43
40
args . projectId ,
@@ -56,7 +53,7 @@ export class StorageEmulator implements EmulatorInstance {
56
53
}
57
54
58
55
get rules ( ) : StorageRulesetInstance | undefined {
59
- return this . _rules ;
56
+ return this . _rulesManager . ruleset ;
60
57
}
61
58
62
59
get logger ( ) : EmulatorLogger {
@@ -72,107 +69,23 @@ export class StorageEmulator implements EmulatorInstance {
72
69
async start ( ) : Promise < void > {
73
70
const { host, port } = this . getInfo ( ) ;
74
71
await this . _rulesRuntime . start ( this . args . auto_download ) ;
72
+ await this . _rulesManager . setSourceFile ( this . args . rules ) ;
75
73
this . _app = await createApp ( this . args . projectId , this ) ;
76
-
77
- if ( typeof this . args . rules === "string" ) {
78
- const rulesFile = this . args . rules ;
79
- this . updateRulesSource ( rulesFile ) ;
80
- } else {
81
- this . _rulesetSource = this . args . rules ;
82
- }
83
-
84
- if ( ! this . _rulesetSource || this . _rulesetSource . files . length === 0 ) {
85
- throw new FirebaseError ( "Can not initialize Storage emulator without a rules source / file." ) ;
86
- } else if ( this . _rulesetSource . files . length > 1 ) {
87
- throw new FirebaseError (
88
- "Can not initialize Storage emulator with more than one rules source / file."
89
- ) ;
90
- }
91
-
92
- await this . loadRuleset ( ) ;
93
-
94
- const rulesPath = this . _rulesetSource . files [ 0 ] . name ;
95
- this . _rulesWatcher = chokidar . watch ( rulesPath , { persistent : true , ignoreInitial : true } ) ;
96
- this . _rulesWatcher . on ( "change" , async ( ) => {
97
- // There have been some race conditions reported (on Windows) where reading the
98
- // file too quickly after the watcher fires results in an empty file being read.
99
- // Adding a small delay prevents that at very little cost.
100
- await new Promise ( ( res ) => setTimeout ( res , 5 ) ) ;
101
-
102
- this . _logger . logLabeled (
103
- "BULLET" ,
104
- "storage" ,
105
- `Change detected, updating rules for Cloud Storage...`
106
- ) ;
107
- this . updateRulesSource ( rulesPath ) ;
108
- await this . loadRuleset ( ) ;
109
- } ) ;
110
-
111
74
const server = this . _app . listen ( port , host ) ;
112
75
this . destroyServer = utils . createDestroyer ( server ) ;
113
76
}
114
77
115
- private updateRulesSource ( rulesFile : string ) : void {
116
- this . _rulesetSource = {
117
- files : [
118
- {
119
- name : rulesFile ,
120
- content : fs . readFileSync ( rulesFile ) . toString ( ) ,
121
- } ,
122
- ] ,
123
- } ;
124
- }
125
-
126
- public async loadRuleset ( source ?: Source ) : Promise < StorageRulesIssues > {
127
- if ( source ) {
128
- this . _rulesetSource = source ;
129
- }
130
-
131
- if ( ! this . _rulesetSource ) {
132
- const msg = "Attempting to update ruleset without a source." ;
133
- this . _logger . log ( "WARN" , msg ) ;
134
-
135
- const error = JSON . stringify ( { error : msg } ) ;
136
- return new StorageRulesIssues ( [ error ] , [ ] ) ;
137
- }
138
-
139
- const { ruleset, issues } = await this . _rulesRuntime . loadRuleset ( this . _rulesetSource ) ;
140
-
141
- if ( ! ruleset ) {
142
- issues . all . forEach ( ( issue ) => {
143
- let parsedIssue ;
144
- try {
145
- parsedIssue = JSON . parse ( issue ) ;
146
- } catch {
147
- // Parse manually
148
- }
149
-
150
- if ( parsedIssue ) {
151
- this . _logger . log (
152
- "WARN" ,
153
- `${ parsedIssue . description_ . replace ( / \. $ / , "" ) } in ${
154
- parsedIssue . sourcePosition_ . fileName_
155
- } :${ parsedIssue . sourcePosition_ . line_ } `
156
- ) ;
157
- } else {
158
- this . _logger . log ( "WARN" , issue ) ;
159
- }
160
- } ) ;
161
-
162
- delete this . _rules ;
163
- } else {
164
- this . _rules = ruleset ;
165
- }
166
-
167
- return issues ;
168
- }
169
-
170
78
async connect ( ) : Promise < void > {
171
79
// No-op
172
80
}
173
81
82
+ async setRules ( rules : SourceFile ) : Promise < StorageRulesIssues > {
83
+ return this . _rulesManager . setSourceFile ( rules ) ;
84
+ }
85
+
174
86
async stop ( ) : Promise < void > {
175
87
await this . storageLayer . deleteAll ( ) ;
88
+ await this . _rulesManager . close ( ) ;
176
89
return this . destroyServer ? this . destroyServer ( ) : Promise . resolve ( ) ;
177
90
}
178
91
0 commit comments