File size: 5,192 Bytes
47f5399
 
 
045586e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47f5399
 
045586e
bc22a6c
045586e
 
 
47f5399
045586e
47f5399
 
 
 
045586e
47f5399
 
045586e
47f5399
045586e
47f5399
 
4bf0c24
47f5399
 
 
 
 
bc22a6c
b31641d
045586e
 
b31641d
 
4bf0c24
b31641d
4bf0c24
045586e
 
 
 
 
 
 
 
b31641d
47f5399
b31641d
045586e
b31641d
 
045586e
 
4bf0c24
045586e
4bf0c24
045586e
 
 
 
 
 
 
 
 
 
 
 
4bf0c24
045586e
 
 
 
 
 
 
 
4bf0c24
045586e
 
 
 
 
 
 
 
 
 
4bf0c24
37b203b
045586e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47f5399
045586e
47f5399
045586e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
<!DOCTYPE html>
<html lang="ja">
<head>
  <script src="https://soiz1-eruda3.hf.space/eruda.js"></script>
  <script>eruda.init();</script>
  <meta charset="UTF-8" />
  <title>管理ページ(IP・接続時間表示 + 地図表示)</title>
  <script src="https://cdn.socket.io/4.0.1/socket.io.min.js"></script>
  <link
    rel="stylesheet"
    href="https://unpkg.com/[email protected]/dist/leaflet.css"
    crossorigin=""
  />
  <script
    src="https://unpkg.com/[email protected]/dist/leaflet.js"
    crossorigin=""
  ></script>
  <style>
    #map {
      height: 400px;
      width: 100%;
      border: 1px solid #ccc;
      margin-bottom: 20px;
    }
    table {
      border-collapse: collapse;
      width: 100%;
      margin-bottom: 20px;
    }
    th, td {
      border: 1px solid #ccc;
      padding: 8px;
      text-align: left;
    }
    th {
      background-color: #eee;
    }
    .highlight {
      background-color: #f99;
      transition: background-color 1s ease;
    }
  </style>
</head>
<body>
  <div id="map"></div>

  <h1>現在の接続ユーザー数: <span id="userCount">0</span></h1>
  <div>更新はページ再読み込みで行います。</div>
  <table>
    <thead>
      <tr>
        <th>Socket ID</th>
        <th>IPアドレス</th>
        <th>接続時間</th>
        <th>切断時間</th>
      </tr>
    </thead>
    <tbody id="userTableBody"></tbody>
  </table>

  <script>
    const socket = io("https://web-socket-server-14ap.onrender.com/");
    const STORAGE_KEY = "userSessions";

    let previousSessions = JSON.parse(localStorage.getItem(STORAGE_KEY) || "{}");

    const userCountElem = document.getElementById("userCount");
    const tbody = document.getElementById("userTableBody");

    const map = L.map('map').setView([35.681236, 139.767125], 5);
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      maxZoom: 18,
      attribution: '© OpenStreetMap contributors'
    }).addTo(map);

    let markers = {};

    function createCircleMarker(lat, lon, color, popupText) {
      return L.circleMarker([lat, lon], {
        radius: 10,
        fillColor: color,
        color: '#000',
        weight: 1,
        opacity: 1,
        fillOpacity: 0.9
      }).bindPopup(popupText);
    }

    socket.on("updateUserCount", (count) => {
      userCountElem.textContent = count;
    });

    socket.on("userSessionsUpdate", async (userSessions) => {
      console.log("userSessionsUpdate受信", userSessions);

      tbody.innerHTML = "";

      for (let key in markers) {
        map.removeLayer(markers[key]);
      }
      markers = {};

      const positions = {};
      for (const [socketId, info] of Object.entries(userSessions)) {
        if (info.loc) {
          const [lat, lon] = info.loc.split(',').map(parseFloat);
          if (!isNaN(lat) && !isNaN(lon)) {
            positions[socketId] = { lat, lon };
          }
        }
      }

      for (const [socketId, info] of Object.entries(userSessions)) {
        const tr = document.createElement("tr");

        function createTd(text, elementKey) {
          const td = document.createElement("td");
          td.textContent = text;

          const prevValue = previousSessions[socketId]?.[elementKey];
          const currValue = info[elementKey];
          const changed = prevValue !== currValue;

          if (changed) {
            td.classList.add("highlight");
            setTimeout(() => td.classList.remove("highlight"), 1000);
          }

          return td;
        }

        tr.appendChild(createTd(socketId, "socketId"));
        tr.appendChild(createTd(info.ip || "-", "ip"));
        tr.appendChild(createTd(info.connectTime ? new Date(info.connectTime).toLocaleString() : "-", "connectTime"));
        tr.appendChild(createTd(info.disconnectTime ? new Date(info.disconnectTime).toLocaleString() : "-", "disconnectTime"));

        tbody.appendChild(tr);

        const pos = positions[socketId];
        if (pos) {
          const prevPos = previousSessions[socketId]?.geoPosition;
          let changedPos = true;
          if (prevPos && Math.abs(prevPos.lat - pos.lat) < 0.0001 && Math.abs(prevPos.lon - pos.lon) < 0.0001) {
            changedPos = false;
          }

          const color = info.disconnectTime
            ? "gray"
            : changedPos
              ? "red"
              : "black";

          const marker = createCircleMarker(pos.lat, pos.lon, color, `SocketID: ${socketId}<br>IP: ${info.ip || "-"}`);
          marker.addTo(map);
          markers[socketId] = marker;
        }
      }

      const markerPositions = Object.values(markers).map(m => m.getLatLng());
      if (markerPositions.length > 0) {
        const group = L.featureGroup(Object.values(markers));
        map.fitBounds(group.getBounds().pad(0.5));
      }

      const sessionsToStore = {};
      for (const [socketId, info] of Object.entries(userSessions)) {
        sessionsToStore[socketId] = {
          ...info,
          geoPosition: positions[socketId] || null
        };
      }
      localStorage.setItem(STORAGE_KEY, JSON.stringify(sessionsToStore));
      previousSessions = sessionsToStore;
    });
  </script>
</body>
</html>