@things-factory/weather 9.1.19 → 10.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/services/chrome-renderer.js +10 -2
- package/dist-server/services/chrome-renderer.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/client/tsconfig.json +0 -11
- package/server/controllers/open-meteo-adapter.ts +0 -96
- package/server/controllers/types.ts +0 -63
- package/server/controllers/weather-controller.ts +0 -192
- package/server/index.ts +0 -1
- package/server/routers/geo-router.ts +0 -297
- package/server/routers/weather-router.ts +0 -8
- package/server/routes.ts +0 -10
- package/server/services/chrome-renderer.ts +0 -206
- package/server/services/data.json +0 -8438
- package/server/services/headless-pool.ts +0 -34
- package/server/tsconfig.json +0 -10
- package/server/utils/svg-utils.ts +0 -108
- package/server/utils/tile-utils.ts +0 -77
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Weather Service Headless Pool
|
|
3
|
-
* Using the unified headless pool system from @things-factory/shell
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { getOrCreateHeadlessPool, getAllPoolStats, HEADLESS_POOL_ARGUMENT_SETS } from '@things-factory/shell'
|
|
7
|
-
|
|
8
|
-
// Create the weather pool instance
|
|
9
|
-
const weatherPool = getOrCreateHeadlessPool('weather', {
|
|
10
|
-
min: 1,
|
|
11
|
-
max: 5,
|
|
12
|
-
headless: 'new', // Keep 'new' for weather compatibility
|
|
13
|
-
args: [
|
|
14
|
-
...HEADLESS_POOL_ARGUMENT_SETS.basic,
|
|
15
|
-
...HEADLESS_POOL_ARGUMENT_SETS.keychain_safe,
|
|
16
|
-
...HEADLESS_POOL_ARGUMENT_SETS.security_enhanced
|
|
17
|
-
],
|
|
18
|
-
acquireTimeoutMillis: 10000,
|
|
19
|
-
idleTimeoutMillis: 30000, // 30초 후 유휴 인스턴스 제거
|
|
20
|
-
testOnBorrow: true,
|
|
21
|
-
enableCleanup: true
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* 헤드리스 브라우저 풀 가져오기 (싱글톤 패턴)
|
|
26
|
-
*/
|
|
27
|
-
export function getBrowserPool() {
|
|
28
|
-
return {
|
|
29
|
-
acquire: () => weatherPool.acquire(),
|
|
30
|
-
release: (resource: any) => weatherPool.release(resource),
|
|
31
|
-
drain: () => weatherPool.cleanup(),
|
|
32
|
-
clear: () => weatherPool.reset()
|
|
33
|
-
}
|
|
34
|
-
}
|
package/server/tsconfig.json
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SVG 생성 유틸리티 함수
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* SVG 시작 태그 생성
|
|
7
|
-
*/
|
|
8
|
-
export function createSvgStart(width: number = 256, height: number = 256): string {
|
|
9
|
-
return `<svg width="${width}" height="${height}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">`
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* SVG 종료 태그 생성
|
|
14
|
-
*/
|
|
15
|
-
export function createSvgEnd(): string {
|
|
16
|
-
return '</svg>'
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* SVG 그라데이션 정의 생성
|
|
21
|
-
*/
|
|
22
|
-
export function createSvgDefs(gradients: Array<{ id: string; color: string; opacity?: number }>): string {
|
|
23
|
-
let defs = '<defs>'
|
|
24
|
-
|
|
25
|
-
gradients.forEach(gradient => {
|
|
26
|
-
const opacity = gradient.opacity !== undefined ? gradient.opacity : 0.8
|
|
27
|
-
defs += `
|
|
28
|
-
<radialGradient id="${gradient.id}" cx="50%" cy="50%" r="50%" fx="50%" fy="50%">
|
|
29
|
-
<stop offset="0%" style="stop-color:${gradient.color}; stop-opacity:${opacity}" />
|
|
30
|
-
<stop offset="100%" style="stop-color:${gradient.color}; stop-opacity:0" />
|
|
31
|
-
</radialGradient>`
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
defs += '</defs>'
|
|
35
|
-
return defs
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* SVG 원 요소 생성
|
|
40
|
-
*/
|
|
41
|
-
export function createSvgCircle(cx: number, cy: number, radius: number, fill: string, opacity?: number): string {
|
|
42
|
-
const opacityAttr = opacity !== undefined ? ` opacity="${opacity}"` : ''
|
|
43
|
-
return `<circle cx="${cx}" cy="${cy}" r="${radius}" fill="${fill}"${opacityAttr} />`
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* SVG 라인 요소 생성
|
|
48
|
-
*/
|
|
49
|
-
export function createSvgLine(
|
|
50
|
-
x1: number,
|
|
51
|
-
y1: number,
|
|
52
|
-
x2: number,
|
|
53
|
-
y2: number,
|
|
54
|
-
stroke: string,
|
|
55
|
-
strokeWidth: number = 1,
|
|
56
|
-
opacity?: number
|
|
57
|
-
): string {
|
|
58
|
-
const opacityAttr = opacity !== undefined ? ` opacity="${opacity}"` : ''
|
|
59
|
-
return `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" stroke="${stroke}" stroke-width="${strokeWidth}"${opacityAttr} />`
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* SVG 화살표 생성 (바람 방향 표시용)
|
|
64
|
-
*/
|
|
65
|
-
export function createSvgArrow(
|
|
66
|
-
x: number,
|
|
67
|
-
y: number,
|
|
68
|
-
angle: number,
|
|
69
|
-
length: number,
|
|
70
|
-
color: string,
|
|
71
|
-
strokeWidth: number = 1,
|
|
72
|
-
opacity?: number
|
|
73
|
-
): string {
|
|
74
|
-
const opacityAttr = opacity !== undefined ? ` opacity="${opacity}"` : ''
|
|
75
|
-
|
|
76
|
-
// 라디안으로 변환
|
|
77
|
-
const rad = (angle * Math.PI) / 180
|
|
78
|
-
|
|
79
|
-
// 화살표 끝점 계산
|
|
80
|
-
const endX = x + length * Math.cos(rad)
|
|
81
|
-
const endY = y + length * Math.sin(rad)
|
|
82
|
-
|
|
83
|
-
// 화살표 머리 계산 (각도에서 30도 틀어진 두 지점)
|
|
84
|
-
const headSize = length * 0.25
|
|
85
|
-
const head1X = endX - headSize * Math.cos(rad + Math.PI / 6)
|
|
86
|
-
const head1Y = endY - headSize * Math.sin(rad + Math.PI / 6)
|
|
87
|
-
const head2X = endX - headSize * Math.cos(rad - Math.PI / 6)
|
|
88
|
-
const head2Y = endY - headSize * Math.sin(rad - Math.PI / 6)
|
|
89
|
-
|
|
90
|
-
return `
|
|
91
|
-
<g${opacityAttr}>
|
|
92
|
-
<line x1="${x}" y1="${y}" x2="${endX}" y2="${endY}" stroke="${color}" stroke-width="${strokeWidth}" />
|
|
93
|
-
<line x1="${endX}" y1="${endY}" x2="${head1X}" y2="${head1Y}" stroke="${color}" stroke-width="${strokeWidth}" />
|
|
94
|
-
<line x1="${endX}" y1="${endY}" x2="${head2X}" y2="${head2Y}" stroke="${color}" stroke-width="${strokeWidth}" />
|
|
95
|
-
</g>
|
|
96
|
-
`
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* 날씨 타일용 SVG 생성
|
|
101
|
-
*/
|
|
102
|
-
export function createWeatherTileSvg(width: number, height: number, elements: string[]): string {
|
|
103
|
-
return `
|
|
104
|
-
${createSvgStart(width, height)}
|
|
105
|
-
${elements.join('\n')}
|
|
106
|
-
${createSvgEnd()}
|
|
107
|
-
`
|
|
108
|
-
}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 타일 좌표 관련 유틸리티 함수
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export interface TileBounds {
|
|
6
|
-
west: number
|
|
7
|
-
south: number
|
|
8
|
-
east: number
|
|
9
|
-
north: number
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* 타일 좌표를 위경도 범위로 변환
|
|
14
|
-
*/
|
|
15
|
-
export function getTileBounds(z: number, x: number, y: number): TileBounds {
|
|
16
|
-
const n = Math.pow(2, z)
|
|
17
|
-
const west = (x / n) * 360 - 180
|
|
18
|
-
const east = ((x + 1) / n) * 360 - 180
|
|
19
|
-
const north = Math.atan(Math.sinh(Math.PI * (1 - (2 * y) / n))) * (180 / Math.PI)
|
|
20
|
-
const south = Math.atan(Math.sinh(Math.PI * (1 - (2 * (y + 1)) / n))) * (180 / Math.PI)
|
|
21
|
-
|
|
22
|
-
return { west, south, east, north }
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* 위경도를 타일 좌표로 변환
|
|
27
|
-
*/
|
|
28
|
-
export function latLonToTile(lat: number, lon: number, zoom: number): { x: number; y: number } {
|
|
29
|
-
const latRad = (lat * Math.PI) / 180
|
|
30
|
-
const n = Math.pow(2, zoom)
|
|
31
|
-
const x = Math.floor(((lon + 180) / 360) * n)
|
|
32
|
-
const y = Math.floor(((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2) * n)
|
|
33
|
-
|
|
34
|
-
return { x, y }
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 픽셀 좌표를 위경도로 변환
|
|
39
|
-
*/
|
|
40
|
-
export function pixelToLatLon(x: number, y: number, z: number): { lat: number; lon: number } {
|
|
41
|
-
const size = Math.pow(2, z) * 256
|
|
42
|
-
const lon = (x / size) * 360 - 180
|
|
43
|
-
|
|
44
|
-
const n = Math.PI - (2 * Math.PI * y) / size
|
|
45
|
-
const lat = (180 / Math.PI) * Math.atan(0.5 * (Math.exp(n) - Math.exp(-n)))
|
|
46
|
-
|
|
47
|
-
return { lat, lon }
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 위경도를 픽셀 좌표로 변환
|
|
52
|
-
*/
|
|
53
|
-
export function latLonToPixel(lat: number, lon: number, z: number): { x: number; y: number } {
|
|
54
|
-
const size = Math.pow(2, z) * 256
|
|
55
|
-
const x = ((lon + 180) / 360) * size
|
|
56
|
-
|
|
57
|
-
const latRad = (lat * Math.PI) / 180
|
|
58
|
-
const y = ((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2) * size
|
|
59
|
-
|
|
60
|
-
return { x, y }
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* 두 위경도 사이의 거리 계산 (Haversine 공식)
|
|
65
|
-
*/
|
|
66
|
-
export function getDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
|
|
67
|
-
const R = 6371 // 지구 반경 (km)
|
|
68
|
-
const dLat = (lat2 - lat1) * (Math.PI / 180)
|
|
69
|
-
const dLon = (lon2 - lon1) * (Math.PI / 180)
|
|
70
|
-
|
|
71
|
-
const a =
|
|
72
|
-
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
|
|
73
|
-
Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) * Math.sin(dLon / 2) * Math.sin(dLon / 2)
|
|
74
|
-
|
|
75
|
-
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
|
|
76
|
-
return R * c
|
|
77
|
-
}
|