soiz1 commited on
Commit
37b203b
·
1 Parent(s): 678e1df

Update web-socket.html

Browse files
Files changed (1) hide show
  1. web-socket.html +129 -148
web-socket.html CHANGED
@@ -2,63 +2,67 @@
2
  <html lang="ja">
3
  <head>
4
  <script src="https://soiz1-eruda3.hf.space/eruda.js"></script>
5
- <script>eruda.init();</script>
6
- <meta charset="UTF-8" />
7
- <title>管理ページ(IP・接続時間表示 + 地図表示)</title>
8
- <script src="https://cdn.socket.io/4.0.1/socket.io.min.js"></script>
9
- <link
10
- rel="stylesheet"
11
- href="https://unpkg.com/[email protected]/dist/leaflet.css"
12
- crossorigin=""
13
- />
14
- <script
15
- src="https://unpkg.com/[email protected]/dist/leaflet.js"
16
- crossorigin=""
17
- ></script>
18
- <style>
19
- #map {
20
- height: 400px;
21
- width: 100%;
22
- border: 1px solid #ccc;
23
- margin-bottom: 20px;
24
- }
25
- table {
26
- border-collapse: collapse;
27
- width: 100%;
28
- margin-bottom: 20px;
29
- }
30
- th, td {
31
- border: 1px solid #ccc;
32
- padding: 8px;
33
- text-align: left;
34
- }
35
- th {
36
- background-color: #eee;
37
- }
38
- .highlight {
39
- background-color: #f99;
40
- transition: background-color 1s ease;
41
- }
42
- </style>
43
  </head>
44
  <body>
45
- <div id="map"></div>
46
 
47
- <h1>現在の接続ユーザー数: <span id="userCount">0</span></h1>
48
- <div>更新はページ再読み込みで行います。</div>
49
- <table>
50
  <thead>
51
- <tr>
52
  <th>Socket ID</th>
53
  <th>IPアドレス</th>
54
  <th>接続時間</th>
55
  <th>切断時間</th>
56
- </tr>
 
 
 
 
57
  </thead>
58
  <tbody id="userTableBody"></tbody>
59
- </table>
60
 
61
- <script>
62
  const socket = io("https://web-socket-server-14ap.onrender.com/");
63
 
64
  const STORAGE_KEY = "userSessions";
@@ -70,123 +74,100 @@
70
 
71
  const map = L.map('map').setView([35.681236, 139.767125], 5);
72
  L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
73
- maxZoom: 18,
74
- attribution: '© OpenStreetMap contributors'
75
  }).addTo(map);
76
 
77
  let markers = {};
78
 
79
- async function fetchGeo(ip) {
80
- try {
81
- const response = await fetch("https://soiz1-ip-address-api.hf.space/ip", {
82
- method: "POST",
83
- headers: { "Content-Type": "application/json" },
84
- body: JSON.stringify({ ip: ip })
85
- });
86
- if (!response.ok) {
87
- console.error("APIエラー:", response.status);
88
- return null;
89
- }
90
- const data = await response.json();
91
- if (data && data.location && typeof data.location.latitude === "number" && typeof data.location.longitude === "number") {
92
- return { lat: data.location.latitude, lon: data.location.longitude };
93
- }
94
- return null;
95
- } catch (error) {
96
- console.error("fetchGeo失敗:", error);
97
- return null;
98
- }
99
- }
100
-
101
  function createCircleMarker(lat, lon, color, popupText) {
102
- return L.circleMarker([lat, lon], {
103
- radius: 10,
104
- fillColor: color,
105
- color: '#000',
106
- weight: 1,
107
- opacity: 1,
108
- fillOpacity: 0.9
109
- }).bindPopup(popupText);
110
  }
111
 
112
  socket.on("updateUserCount", (count) => {
113
- userCountElem.textContent = count;
114
  });
115
 
116
- socket.on("userSessionsUpdate", async (userSessions) => {
117
- console.log("userSessionsUpdate受信", userSessions);
118
-
119
- tbody.innerHTML = "";
120
-
121
- for (let key in markers) {
122
- map.removeLayer(markers[key]);
123
- }
124
- markers = {};
125
-
126
- const positions = {};
127
- await Promise.all(Object.entries(userSessions).map(async ([socketId, info]) => {
128
- positions[socketId] = await fetchGeo(info.ip);
129
- }));
130
-
131
- for (const [socketId, info] of Object.entries(userSessions)) {
132
- const tr = document.createElement("tr");
133
 
134
- function createTd(text, elementKey) {
135
- const td = document.createElement("td");
136
- td.textContent = text;
137
 
138
- const prevValue = previousSessions[socketId] ? previousSessions[socketId][elementKey] : undefined;
139
- const currValue = info[elementKey];
140
-
141
- const changed = prevValue !== currValue;
142
-
143
- if (changed) {
144
- td.classList.add("highlight");
145
- setTimeout(() => td.classList.remove("highlight"), 1000);
146
- }
147
-
148
- return td;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  }
150
 
151
- tr.appendChild(createTd(socketId, "socketId"));
152
- tr.appendChild(createTd(info.ip || "-", "ip"));
153
- tr.appendChild(createTd(info.connectTime ? new Date(info.connectTime).toLocaleString() : "-", "connectTime"));
154
- tr.appendChild(createTd(info.disconnectTime ? new Date(info.disconnectTime).toLocaleString() : "-", "disconnectTime"));
155
-
156
- tbody.appendChild(tr);
157
-
158
- const pos = positions[socketId];
159
- if (pos) {
160
- const prevPos = previousSessions[socketId]?.geoPosition;
161
- let changedPos = true;
162
- if (prevPos && Math.abs(prevPos.lat - pos.lat) < 0.0001 && Math.abs(prevPos.lon - pos.lon) < 0.0001) {
163
- changedPos = false;
164
- }
165
- const color = changedPos ? 'red' : 'black';
166
-
167
- const marker = createCircleMarker(pos.lat, pos.lon, color, `SocketID: ${socketId}<br>IP: ${info.ip || "-"}`);
168
- marker.addTo(map);
169
- markers[socketId] = marker;
170
  }
171
- }
172
-
173
- const markerPositions = Object.values(markers).map(m => m.getLatLng());
174
- if (markerPositions.length > 0) {
175
- const group = L.featureGroup(Object.values(markers));
176
- map.fitBounds(group.getBounds().pad(0.5));
177
- }
178
-
179
- const sessionsToStore = {};
180
- for (const [socketId, info] of Object.entries(userSessions)) {
181
- sessionsToStore[socketId] = {
182
- ...info,
183
- geoPosition: positions[socketId] || null
184
- };
185
- }
186
- localStorage.setItem(STORAGE_KEY, JSON.stringify(sessionsToStore));
187
- previousSessions = sessionsToStore;
188
  });
189
 
190
- </script>
191
  </body>
192
- </html>
 
2
  <html lang="ja">
3
  <head>
4
  <script src="https://soiz1-eruda3.hf.space/eruda.js"></script>
5
+ <script>eruda.init();</script>
6
+ <meta charset="UTF-8" />
7
+ <title>管理ページ(IP・接続時間表示 + 地図表示)</title>
8
+ <script src="https://cdn.socket.io/4.0.1/socket.io.min.js"></script>
9
+ <link
10
+ rel="stylesheet"
11
+ href="https://unpkg.com/[email protected]/dist/leaflet.css"
12
+ crossorigin=""
13
+ />
14
+ <script
15
+ src="https://unpkg.com/[email protected]/dist/leaflet.js"
16
+ crossorigin=""
17
+ ></script>
18
+ <style>
19
+ #map {
20
+ height: 400px;
21
+ width: 100%;
22
+ border: 1px solid #ccc;
23
+ margin-bottom: 20px;
24
+ }
25
+ table {
26
+ border-collapse: collapse;
27
+ width: 100%;
28
+ margin-bottom: 20px;
29
+ }
30
+ th, td {
31
+ border: 1px solid #ccc;
32
+ padding: 8px;
33
+ text-align: left;
34
+ }
35
+ th {
36
+ background-color: #eee;
37
+ }
38
+ .highlight {
39
+ background-color: #f99;
40
+ transition: background-color 1s ease;
41
+ }
42
+ </style>
43
  </head>
44
  <body>
45
+ <div id="map"></div>
46
 
47
+ <h1>現在の接続ユーザー数: <span id="userCount">0</span></h1>
48
+ <div>更新はページ再読み込みで行います。</div>
49
+ <table>
50
  <thead>
51
+ <tr>
52
  <th>Socket ID</th>
53
  <th>IPアドレス</th>
54
  <th>接続時間</th>
55
  <th>切断時間</th>
56
+ <th>位置情報</th>
57
+ <th>都市</th>
58
+ <th>地域</th>
59
+ <th>国</th>
60
+ </tr>
61
  </thead>
62
  <tbody id="userTableBody"></tbody>
63
+ </table>
64
 
65
+ <script>
66
  const socket = io("https://web-socket-server-14ap.onrender.com/");
67
 
68
  const STORAGE_KEY = "userSessions";
 
74
 
75
  const map = L.map('map').setView([35.681236, 139.767125], 5);
76
  L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
77
+ maxZoom: 18,
78
+ attribution: '© OpenStreetMap contributors'
79
  }).addTo(map);
80
 
81
  let markers = {};
82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  function createCircleMarker(lat, lon, color, popupText) {
84
+ return L.circleMarker([lat, lon], {
85
+ radius: 10,
86
+ fillColor: color,
87
+ color: '#000',
88
+ weight: 1,
89
+ opacity: 1,
90
+ fillOpacity: 0.9
91
+ }).bindPopup(popupText);
92
  }
93
 
94
  socket.on("updateUserCount", (count) => {
95
+ userCountElem.textContent = count;
96
  });
97
 
98
+ socket.on("userSessionsUpdate", (userSessions) => {
99
+ console.log("userSessionsUpdate受信", userSessions);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
+ tbody.innerHTML = "";
 
 
102
 
103
+ for (let key in markers) {
104
+ map.removeLayer(markers[key]);
105
+ }
106
+ markers = {};
107
+
108
+ for (const [socketId, info] of Object.entries(userSessions)) {
109
+ const tr = document.createElement("tr");
110
+
111
+ function createTd(text, elementKey) {
112
+ const td = document.createElement("td");
113
+ td.textContent = text;
114
+
115
+ const prevValue = previousSessions[socketId] ? previousSessions[socketId][elementKey] : undefined;
116
+ const currValue = info[elementKey];
117
+
118
+ const changed = prevValue !== currValue;
119
+
120
+ if (changed) {
121
+ td.classList.add("highlight");
122
+ setTimeout(() => td.classList.remove("highlight"), 1000);
123
+ }
124
+
125
+ return td;
126
+ }
127
+
128
+ tr.appendChild(createTd(socketId, "socketId"));
129
+ tr.appendChild(createTd(info.ip || "-", "ip"));
130
+ tr.appendChild(createTd(info.connectTime ? new Date(info.connectTime).toLocaleString() : "-", "connectTime"));
131
+ tr.appendChild(createTd(info.disconnectTime ? new Date(info.disconnectTime).toLocaleString() : "-", "disconnectTime"));
132
+ tr.appendChild(createTd(info.loc || "-", "loc"));
133
+ tr.appendChild(createTd(info.city || "-", "city"));
134
+ tr.appendChild(createTd(info.region || "-", "region"));
135
+ tr.appendChild(createTd(info.country || "-", "country"));
136
+
137
+ tbody.appendChild(tr);
138
+
139
+ // 位置情報がある場合、地図にマーカーを追加
140
+ if (info.loc) {
141
+ const [lat, lon] = info.loc.split(',').map(Number);
142
+ const prevLoc = previousSessions[socketId]?.loc;
143
+ const changedPos = prevLoc !== info.loc;
144
+ const color = changedPos ? 'red' : 'blue';
145
+
146
+ const locationText = [
147
+ `SocketID: ${socketId}`,
148
+ `IP: ${info.ip || "-"}`,
149
+ `都市: ${info.city || "-"}`,
150
+ `地域: ${info.region || "-"}`,
151
+ `国: ${info.country || "-"}`
152
+ ].join('<br>');
153
+
154
+ const marker = createCircleMarker(lat, lon, color, locationText);
155
+ marker.addTo(map);
156
+ markers[socketId] = marker;
157
+ }
158
  }
159
 
160
+ // マーカーがある場合、地図を適切な範囲に調整
161
+ if (Object.keys(markers).length > 0) {
162
+ const group = L.featureGroup(Object.values(markers));
163
+ map.fitBounds(group.getBounds().pad(0.5));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  }
165
+
166
+ // セッション情報をローカルストレージに保存
167
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(userSessions));
168
+ previousSessions = userSessions;
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  });
170
 
171
+ </script>
172
  </body>
173
+ </html>