Skip to content

Commit 0505a9b

Browse files
committed
Set IMAGEPATH for all maps
1 parent dfea499 commit 0505a9b

29 files changed

Lines changed: 180 additions & 48 deletions

‎docker/.dockerignore‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
!runtime
33
!instantclient
44
!templates
5+
workshop/exercises/mapfiles/tmp/*
6+
!workshop/exercises/mapfiles/tmp/.gitkeep

‎docker/Dockerfile‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,12 @@ ENV MS_DEBUGLEVEL=0 \
155155
MAPSERVER_CONFIG_FILE=/etc/mapserver/mapserver.conf \
156156
MAPSERVER_BASE_PATH= \
157157
MAX_REQUESTS_PER_PROCESS=1000 \
158-
MIN_PROCESSES=1 \
158+
# Keep several MapServer processes running, so concurrent requests don't
159+
# wait for one another (see the warm-up in start-server)
160+
MIN_PROCESSES=2 \
159161
MAX_PROCESSES=5 \
160162
BUSY_TIMEOUT=300 \
161-
IDLE_TIMEOUT=300 \
163+
IDLE_TIMEOUT=3600 \
162164
IO_TIMEOUT=40 \
163165
APACHE_LIMIT_REQUEST_LINE=8190 \
164166
GET_ENV=env \

‎docker/Dockerfile.demo‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ FROM mapserver-workshop
22

33
# Copy workshop files into the image
44
COPY workshop/exercises/mapfiles /etc/mapserver/
5+
6+
RUN chown -R www-data:www-data /etc/mapserver/tmp

‎docker/ReadMe.md‎

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,26 @@ cd D:\GitHub\getting-started-with-mapserver\docker
1717
# MAPSERVER_BRANCH=branch-8-6
1818
1919
# add --no-cache to the command below to force getting the latest code
20+
# it could be months old otherwise!
2021
2122
docker build `
2223
--tag "mapserver-workshop" `
2324
--target=runner `
2425
--build-arg=MAPSERVER_BRANCH=main `
2526
--build-arg=MAPSERVER_REPO=https://github.com/mapserver/mapserver `
27+
--no-cache `
2628
.
2729
30+
# push the image for use in docker-compose and for workshop attendees to pull from DockerHub
31+
# https://mapserver.github.io/getting-started-with-mapserver-demo/ builds from this image
32+
# and needs to be updated if the image is rebuilt with a new MapServer version or branch
33+
# by pushing mapserver-workshop-demo (see below)
2834
docker tag mapserver-workshop geographika/mapserver-workshop
2935
# docker login
3036
# geographika
3137
# docker images
3238
docker push geographika/mapserver-workshop
39+
3340
```
3441

3542
If there are connection issues, try running the following test from the host, and check proxy/DNS settings:
@@ -54,9 +61,12 @@ docker run -it --name mapserver-workshop geographika/mapserver-workshop:latest b
5461

5562
## Build the Demo Image
5663

57-
This image contains both MapServer and all the MapServer workshop files so it can be deployed
64+
This image contains both MapServer (based on the image above) and all the MapServer workshop files so it can be deployed
5865
in the cloud. This is not required for the workshop itself, and users will use local files from the repository.
5966

67+
The URL for the deployed MapServer is currently https://mapserver-workshop-k8hvw.ondigitalocean.app/
68+
and is used for the online demo at https://mapserver.github.io/getting-started-with-mapserver-demo/
69+
6070
It first requires the `mapserver-workshop` Docker image above is built and available locally.
6171

6272
```
@@ -68,9 +78,6 @@ docker build -f docker/Dockerfile.demo `
6878
--tag "mapserver-workshop-demo" `
6979
.
7080
71-
# docker run -it --name mapserver-workshop-demo -p 8080:8080 mapserver-workshop-demo
72-
# http://localhost:8080/
73-
7481
docker tag mapserver-workshop-demo geographika/mapserver-workshop-demo
7582
7683
# docker login
@@ -87,4 +94,11 @@ doctl auth init -t dop_v1_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
8794
doctl registry login
8895
docker tag mapserver-workshop-demo registry.digitalocean.com/geographika/mapserver-workshop-demo:latest
8996
docker push registry.digitalocean.com/geographika/mapserver-workshop-demo:latest
97+
doctl registry repository list-tags mapserver-workshop-demo
98+
```
99+
100+
To test demo locally:
101+
```
102+
docker run -it --rm --name mapserver-workshop-demo -p 8080:8080 mapserver-workshop-demo
103+
# http://localhost:8080/
90104
```

‎docker/runtime/usr/local/bin/start-server‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,25 @@ trap '' WINCH
2121

2222
rm -f "${APACHE_PID_FILE}"
2323

24+
# Warm up mod_fcgid. It only starts a new MapServer process without delay
25+
# when none is busy; otherwise a request waits 1 second for a busy process
26+
# to become free, so short concurrent requests (e.g. GetStyles + GetMap)
27+
# are slow. Sending MIN_PROCESSES requests at once, right after start-up,
28+
# starts that many processes, and FcgidMinProcessesPerClass keeps them alive.
29+
(
30+
# Wait until Apache accepts connections (up to 30 seconds)
31+
for _ in $(seq 30); do
32+
(exec 3<>/dev/tcp/127.0.0.1/8080) 2>/dev/null && break
33+
sleep 1
34+
done
35+
for _ in $(seq "${MIN_PROCESSES}"); do
36+
(
37+
exec 3<>/dev/tcp/127.0.0.1/8080 \
38+
&& printf 'GET / HTTP/1.0\r\nHost: localhost\r\n\r\n' >&3 \
39+
&& cat <&3 >/dev/null
40+
) &
41+
done
42+
wait
43+
) &
44+
2445
exec apache2 -DFOREGROUND

‎workshop/content/docs/outputs/wcs.md‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ WEB
7777
"wcs_srs" "EPSG:4326 EPSG:3857"
7878
"wcs_title" "Example WCS Mapfile"
7979
"wcs_description" "Test description"
80-
"wcs_onlineresource" "http://localhost:7000/"
8180
END
8281
END
8382
```

‎workshop/content/zensical.toml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ nav = [
5353
{ "Clusters" = "advanced/clusters.md" },
5454
{ "SLD" = "advanced/sld.md" },
5555
{ "STAC" = "advanced/stac.md" },
56-
{ "Non-EPSG CRSs" = "advanced/other-projections.md" }
56+
{ "Non-EPSG CRSs" = "advanced/other-projections.md" },
57+
{ "GeoStyler" = "advanced/geostyler.md" }
5758
]},
5859
{ "Summary" = "summary.md" },
5960
{ "Credits and Thanks" = "credits.md" }

‎workshop/exercises/app/css/geostyler.css‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,30 @@ html, body {
129129
.code .cm-content {
130130
padding-bottom: 40px;
131131
}
132+
133+
/* `display: flex` on .code would otherwise override the hidden attribute */
134+
.code[hidden] {
135+
display: none;
136+
}
137+
138+
/* Tabs in the bottom-right panel title bar */
139+
.tabs {
140+
display: flex;
141+
gap: 4px;
142+
padding-bottom: 0;
143+
}
144+
145+
.tab {
146+
font: inherit;
147+
color: #777;
148+
background: none;
149+
border: none;
150+
border-bottom: 2px solid transparent;
151+
padding: 0 6px 3px;
152+
cursor: pointer;
153+
}
154+
155+
.tab.active {
156+
color: #444;
157+
border-bottom-color: #444;
158+
}

‎workshop/exercises/app/geostyler.html‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,12 @@
3838
</div>
3939
</div>
4040
<div class="panel">
41-
<div class="panel-title">SLD (applied in OpenLayers)</div>
41+
<div class="panel-title tabs" role="tablist">
42+
<button class="tab active" role="tab" data-tab="sld-text">SLD</button>
43+
<button class="tab" role="tab" data-tab="geostyler-text">GeoStyler style (used by OpenLayers)</button>
44+
</div>
4245
<div id="sld-text" class="code"></div>
46+
<div id="geostyler-text" class="code" hidden></div>
4347
</div>
4448
</section>
4549
</main>

‎workshop/exercises/app/js/geostyler.js‎

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import xmlFormat from 'xml-formatter';
1414
import { EditorView, basicSetup } from 'codemirror';
1515
import { EditorState } from '@codemirror/state';
1616
import { xml } from '@codemirror/lang-xml';
17+
import { json } from '@codemirror/lang-json';
1718

1819
const mapserverUrl = import.meta.env.VITE_MAPSERVER_BASE_URL;
1920
const mapfilesPath = import.meta.env.VITE_MAPFILES_PATH;
@@ -33,6 +34,7 @@ const demoLayers = [
3334
{ id: 'notched-rect', type: 'point' },
3435
{ id: 'square-spaced', type: 'polygon' },
3536
{ id: 'wave', type: 'polygon' },
37+
{ id: 'fills', type: 'polygon' },
3638
];
3739

3840
const sldParser = new SLDParser();
@@ -72,6 +74,7 @@ function setText(view, text) {
7274
const classView = createViewer('class-text', mapfileLanguage);
7375
const symView = createViewer('sym-text', mapfileLanguage);
7476
const sldView = createViewer('sld-text', xml());
77+
const geostylerView = createViewer('geostyler-text', json());
7578

7679
function showSld(text) {
7780
let formatted = text;
@@ -124,6 +127,7 @@ async function fetchSld(layerConfig) {
124127

125128
/**
126129
* Convert an SLD to an OpenLayers style with GeoStyler, and apply it.
130+
* Returns the GeoStyler style the OpenLayers style was created from.
127131
*/
128132
async function applySld(sldXmlString, vectorLayer) {
129133
const gs = await sldParser.readStyle(sldXmlString);
@@ -148,6 +152,7 @@ async function applySld(sldXmlString, vectorLayer) {
148152
console.log(`OpenLayers style for layer ${vectorLayer.get('name')}:`, ol.output);
149153

150154
vectorLayer.setStyle(ol.output);
155+
return gs.output;
151156
}
152157

153158
function createVectorLayer(layerConfig) {
@@ -206,19 +211,20 @@ function main() {
206211
const classFile = `${layerConfig.id}.class`;
207212
const symFile = `${layerConfig.id}.sym`;
208213

209-
const [classText, symText, sld] = await Promise.all([
214+
const [classText, symText, { sld, geostylerStyle }] = await Promise.all([
210215
fetchText(`${includesUrl}${classFile}`)
211216
.catch((error) => `# Could not load ${classFile}: ${error.message}`),
212217
fetchOptionalText(`${includesUrl}${symFile}`)
213218
.catch(() => null),
214219
fetchSld(layerConfig)
215220
.then(async (sldXmlString) => {
216-
await applySld(sldXmlString, vectorLayer);
217-
return sldXmlString;
221+
const style = await applySld(sldXmlString, vectorLayer);
222+
return { sld: sldXmlString, geostylerStyle: style };
218223
})
219224
.catch((error) => {
220225
console.error(`Failed to style layer ${layerConfig.id}`, error);
221-
return `Could not load or apply the SLD: ${error.message}`;
226+
const message = `Could not load or apply the SLD: ${error.message}`;
227+
return { sld: message, geostylerStyle: null };
222228
}),
223229
]);
224230

@@ -235,8 +241,24 @@ function main() {
235241
setText(symView, symText ?? '');
236242

237243
showSld(sld);
244+
setText(geostylerView, geostylerStyle
245+
? JSON.stringify(geostylerStyle, null, 2)
246+
: '// No GeoStyler style: see the SLD tab for the error');
238247

239248
mapRight.getLayers().clear();
249+
250+
// Tabs in the bottom-right panel: show one viewer at a time
251+
const tabs = document.querySelectorAll('.tab');
252+
tabs.forEach((tab) => {
253+
tab.addEventListener('click', () => {
254+
tabs.forEach((t) => {
255+
const active = t === tab;
256+
t.classList.toggle('active', active);
257+
document.getElementById(t.dataset.tab).hidden = !active;
258+
});
259+
});
260+
});
261+
240262
mapRight.addLayer(baseLayer());
241263
mapRight.addLayer(vectorLayer);
242264
}

0 commit comments

Comments
 (0)