├── .github
└── workflows
│ ├── dotnet-build-and-test.yml
│ └── dotnet-publish.yml
├── .gitignore
├── AutoUpdater
├── App.xaml
├── App.xaml.cs
├── AssemblyInfo.cs
├── AutoUpdater.csproj
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── MainWindowModel.cs
├── P2PQuakeCommunicator.cs
├── Program.cs
├── Properties
│ └── PublishProfiles
│ │ └── FolderProfile.pubxml
└── Resources
│ ├── icon.ico
│ └── icon.png
├── CLI
├── CLI.csproj
├── Command
│ ├── EEWSubCommand.cs
│ ├── LoggerCommand.cs
│ ├── MapCommand.cs
│ ├── PublisherCommand.cs
│ ├── QuakeSubCommand.cs
│ ├── ServerSubCommand.cs
│ ├── TsunamiSubCommand.cs
│ └── UserquakeSubCommand.cs
├── Grpc
│ ├── Server.cs
│ └── Services
│ │ ├── ObserverService.cs
│ │ └── OperatorService.cs
├── Observers
│ ├── DummyObserver.cs
│ ├── GrpcObserver.cs
│ ├── IObserver.cs
│ ├── ObserverFactory.cs
│ └── PrintObserver.cs
├── Program.cs
├── Properties
│ └── launchSettings.json
├── Protos
│ ├── observer.proto
│ └── operator.proto
└── appsettings.json
├── Client.sln
├── Client
├── App
│ ├── IMediatorContext.cs
│ ├── IOperatable.cs
│ ├── IPeerConfig.cs
│ ├── IPeerState.cs
│ ├── MaintainTimer.cs
│ ├── MediatorContext.cs
│ ├── State
│ │ ├── AbstractState.cs
│ │ ├── ConnectedState.cs
│ │ ├── ConnectingState.cs
│ │ ├── DisconnectedState.cs
│ │ ├── DisconnectingState.cs
│ │ └── MaintenanceState.cs
│ └── Userquake
│ │ ├── Aggregator.cs
│ │ ├── AreaPositions.cs
│ │ └── UserquakeEvaluateEventArgs.cs
├── Application.Designer.cs
├── Application.settings
├── AssemblyInfo.cs
├── Client.csproj
├── Client
│ ├── ClientContext.cs
│ ├── General
│ │ ├── ClientConst.cs
│ │ ├── KeyData.cs
│ │ └── ServerPoint.cs
│ ├── IClientContext.cs
│ ├── IClientContextForState.cs
│ └── State
│ │ ├── AbstractState.cs
│ │ ├── ConnectedState.cs
│ │ ├── EndConnectionState.cs
│ │ ├── FinishedState.cs
│ │ ├── IFinishedState.cs
│ │ ├── NotifyProtocolVersionState.cs
│ │ ├── PeerEchoState.cs
│ │ ├── RequireAllocateKeyState.cs
│ │ ├── RequireAreaPeersState.cs
│ │ ├── RequirePartState.cs
│ │ ├── RequirePeerDataState.cs
│ │ ├── RequirePeerIdState.cs
│ │ ├── RequirePortScanState.cs
│ │ ├── RequireProtocolTimeState.cs
│ │ ├── RequireReallocateKeyState.cs
│ │ └── RequireTemporaryPeerIdState.cs
├── Common
│ ├── General
│ │ ├── Const.cs
│ │ ├── Logger.cs
│ │ └── PeerData.cs
│ └── Net
│ │ ├── AsyncListener.cs
│ │ ├── CRLFSocket.cs
│ │ ├── ISocket.cs
│ │ ├── Packet.cs
│ │ ├── SocketAdapter.cs
│ │ └── UPnP
│ │ └── UPnPUtil.cs
└── Peer
│ ├── Context.cs
│ ├── General
│ ├── Code.cs
│ └── PeerConst.cs
│ ├── IPeerConnector.cs
│ ├── IPeerContext.cs
│ ├── Manager
│ ├── DuplicateRemover.cs
│ ├── NetworkInquiryManager.cs
│ ├── Peer.cs
│ ├── PeerManager.cs
│ └── UserquakeDuplicateRemover.cs
│ └── State
│ ├── AbstractState.cs
│ └── GeneralState.cs
├── ClientTest
├── App
│ ├── MaintainTimerTest.cs
│ ├── MediatorContextCalcProtocolTimeTest.cs
│ ├── MediatorContextUserquakeTest.cs
│ └── Userquake
│ │ ├── AggregatorMultithreadTest.cs
│ │ ├── AggregatorTest.cs
│ │ └── UserquakeEvaluateEventArgsTest.cs
├── ClientTest.csproj
├── Common
│ └── Net
│ │ ├── CRLFSocketParseTest.cs
│ │ ├── CRLFSocketTest.cs
│ │ └── UPnP
│ │ └── UPnPUtilTest.cs
├── Peer
│ └── Manager
│ │ ├── NetworkInquiryManagerTest.cs
│ │ ├── PeerManagerRaiseDataEventTest.cs
│ │ ├── PeerManagerTest.cs
│ │ └── PeerReadLineTest.cs
├── SampleTest.cs
└── TestData
│ └── Peer
│ └── Manager
│ └── PeerManagerRaiseDataEventTest_Smoke.txt
├── DummyPeer
├── DummyPeer.csproj
├── Peer
│ ├── Context.cs
│ └── RandomSender.cs
├── Program.cs
├── README.md
└── ServerCrypto
│ ├── DataSigner.cs
│ ├── KeyDefine.cs
│ ├── KeyGenerator.cs
│ ├── PacketSigner.cs
│ └── PeerKey.cs
├── IPC
├── IPC.cs
└── IPC.csproj
├── JsonApi
├── BasicData.cs
├── Client.cs
├── EEW.cs
├── EEWDetection.cs
├── JMAQuake.cs
├── JMATsunami.cs
├── JsonApi.csproj
├── JsonApiConverterWithTypeDiscriminator.cs
├── UnknownData.cs
└── UserquakeEvaluation.cs
├── LICENSE
├── LambdaMetricsCollector
├── Function.cs
├── LambdaMetricsCollector.csproj
└── Properties
│ ├── PublishProfiles
│ └── FolderProfile.pubxml
│ └── launchSettings.json
├── LegacyPluginSupporter
├── LegacyPluginSupporter.csproj
├── Manager.cs
├── Net
│ ├── CRLFSocket.cs
│ └── Packet.cs
├── Plugin.cs
└── Program.cs
├── LegacyPluginSupporterTest
├── LegacyPluginSupporterTest.csproj
├── ManagerTest.cs
└── Usings.cs
├── Map
├── Controller
│ └── MapDrawer.cs
├── FontResource.Designer.cs
├── FontResource.resx
├── ImageResource.Designer.cs
├── ImageResource.resx
├── Map.csproj
├── Model
│ ├── AbstractDrawer.cs
│ ├── AreapeersDrawer.cs
│ ├── EEWAreas.cs
│ ├── EEWConverter.cs
│ ├── EEWDrawer.cs
│ ├── GeoJson.cs
│ ├── HypocenterDrawer.cs
│ ├── MapLoader.cs
│ ├── ObservationAreas.cs
│ ├── ObservationAreasDrawer.cs
│ ├── ObservationPointsDrawer.cs
│ ├── StationNameShorter.cs
│ ├── Stations.cs
│ ├── Transformation.cs
│ ├── TsunamiAreas.cs
│ ├── TsunamiAreasDrawer.cs
│ ├── UserquakeAreas.cs
│ └── UserquakeDrawer.cs
├── PointResource.Designer.cs
├── PointResource.resx
├── Program.cs
└── Resources
│ ├── Fonts
│ ├── LICENSE_RobotoMono.txt
│ ├── RobotoMono-Bold.ttf
│ └── RobotoMono-Regular.ttf
│ ├── Images
│ ├── confidence.xcf
│ ├── confidence_A.png
│ ├── confidence_B.png
│ ├── confidence_C.png
│ ├── confidence_D.png
│ ├── confidence_E.png
│ ├── confidence_F.png
│ ├── description.png
│ ├── quake_note.png
│ ├── scale.xcf
│ ├── scaleMap.xcf
│ ├── scale_10.png
│ ├── scale_20.png
│ ├── scale_30.png
│ ├── scale_40.png
│ ├── scale_45.png
│ ├── scale_46.png
│ ├── scale_50.png
│ ├── scale_55.png
│ ├── scale_60.png
│ ├── scale_70.png
│ ├── tsunamiCategoryMap.svg
│ ├── tsunami_note_advisory.png
│ ├── tsunami_note_majorwarning.png
│ ├── tsunami_note_warning.png
│ └── userquake_note.png
│ ├── Maps
│ ├── COPYING.LESSERv3
│ ├── COPYINGv3
│ ├── LICENSE.TXT
│ ├── README.md
│ ├── japan-gsi_1024-8bit.png
│ ├── japan-gsi_2048-8bit.png
│ ├── japan-gsi_4096-8bit.png
│ ├── japan-gsi_8192-8bit.png
│ ├── japan-large-gsimaps.xcfbz2
│ ├── japan-small-gsimaps.xcfbz2
│ ├── japan.png
│ ├── japan_gmt.eps
│ ├── japan_gmt_3200dpi.xcfbz2
│ ├── world_1024.png
│ ├── world_242.png
│ ├── world_512.png
│ └── world_640.png
│ └── Points
│ ├── Areas.csv
│ ├── EEWPrefs2EarthquakeAreaCodes.csv
│ ├── EarthquakeAreaCodes.csv
│ ├── README.md
│ ├── Stations.csv
│ ├── TsunamiAreaCodes.csv
│ ├── UserquakeAreas.csv
│ ├── UserquakeAreas2EarthquakeAreaCodes.csv
│ ├── earthquake.json
│ ├── earthquake_0.json
│ ├── earthquake_1.json
│ ├── earthquake_2.json
│ ├── earthquake_3.json
│ ├── earthquake_4.json
│ ├── earthquake_5.json
│ ├── earthquake_6.json
│ ├── earthquake_7.json
│ ├── earthquake_8.json
│ ├── earthquake_9.json
│ ├── tsunami.json
│ └── userquake.json
├── MapTest
├── EarthquakeDrawTest.cs
├── Internationalization.cs
├── MapTest.csproj
├── StationsShorteningTest.cs
├── TestData
│ └── ShorteningTest.csv
├── TsunamiDrawTest.cs
└── UserquakeDrawTest.cs
├── PKCSPeerCrypto
├── PKCSPeerCrypto.csproj
├── Properties
│ └── launchSettings.json
├── Signer.cs
└── Verifier.cs
├── PKCSPeerCryptoTest
├── PKCSPeerCryptoTest.csproj
├── Properties
│ └── launchSettings.json
├── SampleTest.cs
├── SignerTest.cs
└── VerifierTest.cs
├── Updater
├── UpdateClient.cs
├── UpdateEntry.cs
└── Updater.csproj
└── WpfClient
├── App.xaml
├── App.xaml.cs
├── AssemblyInfo.cs
├── Configuration.cs
├── EEWVoice.Designer.cs
├── EEWVoice.resx
├── EPSPDataView
├── DetailItemView.cs
├── EPSPEEWTestView.cs
├── EPSPEEWView.cs
├── EPSPQuakeView.cs
├── EPSPTsunamiView.cs
├── EPSPUserquakeView.cs
└── Factory.cs
├── InformationViewModel.cs
├── License.Designer.cs
├── License.resx
├── LicenseViewModel.cs
├── LicenseWindow.xaml
├── LicenseWindow.xaml.cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Notifications
├── Activator.cs
├── Notifier.cs
├── SoundPlayer.cs
└── SoundPlayerEEW.cs
├── Pages
├── Information.xaml
├── Information.xaml.cs
├── InformationTemplateSelector.cs
├── Informations
│ ├── DetailDescriptionTemplateSelector.cs
│ ├── EEW.xaml
│ ├── EEW.xaml.cs
│ ├── EEWCancelled.xaml
│ ├── EEWCancelled.xaml.cs
│ ├── EEWTest.xaml
│ ├── EEWTest.xaml.cs
│ ├── Earthquake.xaml
│ ├── Earthquake.xaml.cs
│ ├── Tsunami.xaml
│ ├── Tsunami.xaml.cs
│ ├── TsunamiCategoryText.xaml
│ ├── TsunamiCategoryText.xaml.cs
│ ├── Unknown.xaml
│ ├── Unknown.xaml.cs
│ ├── Userquake.xaml
│ └── Userquake.xaml.cs
├── Setting.xaml
├── Setting.xaml.cs
├── Status.xaml
└── Status.xaml.cs
├── Program.cs
├── Properties
└── PublishProfiles
│ └── FolderProfile.pubxml
├── Resource.Designer.cs
├── Resource.resx
├── Resources
├── Examples
│ └── japan_1024.png
├── Icons
│ ├── eruption.svg
│ ├── eruption_black.png
│ ├── eruption_white.png
│ ├── icon.svg
│ ├── p2pquake.ico
│ ├── tsunami.svg
│ ├── tsunami_black.png
│ ├── tsunami_gray.png
│ ├── tsunami_red.png
│ ├── tsunami_white.png
│ ├── tsunami_yellow.png
│ ├── userquake.svg
│ ├── userquake_black.png
│ ├── userquake_gray.png
│ ├── userquake_red.png
│ ├── userquake_white.png
│ └── userquake_yellow.png
├── MapOverlays
│ ├── description.png
│ ├── loading.png
│ ├── loading.xcf
│ ├── quake_note.png
│ ├── tsunami_note_advisory.png
│ ├── tsunami_note_majorwarning.png
│ ├── tsunami_note_warning.png
│ └── userquake_note.png
├── Scales
│ ├── scale_10.png
│ ├── scale_20.png
│ ├── scale_30.png
│ ├── scale_40.png
│ ├── scale_45.png
│ ├── scale_46.png
│ ├── scale_50.png
│ ├── scale_55.png
│ ├── scale_60.png
│ └── scale_70.png
├── Sounds
│ ├── EEW
│ │ ├── 160.mp3
│ │ ├── 161.mp3
│ │ ├── 162.mp3
│ │ ├── 163.mp3
│ │ ├── 164.mp3
│ │ ├── 165.mp3
│ │ ├── 166.mp3
│ │ ├── 167.mp3
│ │ ├── 168.mp3
│ │ ├── 169.mp3
│ │ ├── 170.mp3
│ │ ├── 171.mp3
│ │ ├── 172.mp3
│ │ ├── 173.mp3
│ │ ├── 174.mp3
│ │ ├── 175.mp3
│ │ ├── 176.mp3
│ │ ├── 177.mp3
│ │ ├── 178.mp3
│ │ ├── 179.mp3
│ │ ├── 180.mp3
│ │ ├── 181.mp3
│ │ ├── 182.mp3
│ │ ├── 183.mp3
│ │ ├── 184.mp3
│ │ ├── 185.mp3
│ │ ├── 186.mp3
│ │ ├── 187.mp3
│ │ ├── 188.mp3
│ │ ├── 189.mp3
│ │ ├── 190.mp3
│ │ ├── 191.mp3
│ │ ├── 192.mp3
│ │ ├── 193.mp3
│ │ ├── 194.mp3
│ │ ├── 195.mp3
│ │ ├── 196.mp3
│ │ ├── 197.mp3
│ │ ├── 198.mp3
│ │ ├── 199.mp3
│ │ ├── 360.mp3
│ │ ├── 361.mp3
│ │ ├── 362.mp3
│ │ ├── 363.mp3
│ │ ├── 364.mp3
│ │ ├── 365.mp3
│ │ ├── 366.mp3
│ │ ├── 367.mp3
│ │ ├── 368.mp3
│ │ ├── 369.mp3
│ │ ├── 370.mp3
│ │ ├── 371.mp3
│ │ ├── 372.mp3
│ │ ├── 373.mp3
│ │ ├── 374.mp3
│ │ ├── 375.mp3
│ │ ├── EEW_VOICEVOXproject.vvproj
│ │ ├── announce_areas.mp3
│ │ ├── eew.mp3
│ │ ├── eew_cancelled.mp3
│ │ ├── eew_followup.mp3
│ │ └── guidance.mp3
│ ├── EEW_Beta.mp3
│ ├── P2PQ_Snd0.mp3
│ ├── P2PQ_Snd1.mp3
│ ├── P2PQ_Snd2.mp3
│ ├── P2PQ_Snd3.mp3
│ ├── P2PQ_Snd4.mp3
│ ├── P2PQ_Snd9.mp3
│ └── P2PQ_Sndt.mp3
└── Specifications
│ └── epsp-area.csv
├── RootViewModel.cs
├── SettingViewModel.cs
├── StatusViewModel.cs
├── Updater.cs
├── Utils
├── ScaleConverter.cs
└── TsunamiCategoryConverter.cs
└── WpfClient.csproj
/.github/workflows/dotnet-build-and-test.yml:
--------------------------------------------------------------------------------
1 | name: dotnet build and test
2 |
3 | on:
4 | - push
5 | - pull_request
6 |
7 | # See: https://docs.microsoft.com/ja-jp/dotnet/devops/dotnet-test-github-action
8 | # https://docs.microsoft.com/ja-jp/aspnet/core/host-and-deploy/visual-studio-publish-profiles?view=aspnetcore-5.0#folder-publish-example
9 | # https://github.com/actions/cache/blob/main/examples.md#c---nuget
10 |
11 | env:
12 | NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages
13 |
14 | jobs:
15 | on-windows:
16 | runs-on: windows-latest
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: actions/cache@v4
20 | with:
21 | path: ${{ github.workspace }}/.nuget/packages
22 | key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
23 | restore-keys: |
24 | ${{ runner.os }}-nuget-
25 | - name: Setup .NET 6.0
26 | uses: actions/setup-dotnet@v4
27 | with:
28 | dotnet-version: |
29 | 6.0.x
30 | - name: Build
31 | run: dotnet build
32 | - name: Test
33 | run: dotnet test
34 | on-ubuntu:
35 | runs-on: ubuntu-latest
36 | steps:
37 | - uses: actions/checkout@v4
38 | - uses: actions/cache@v4
39 | with:
40 | path: ${{ github.workspace }}/.nuget/packages
41 | key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
42 | restore-keys: |
43 | ${{ runner.os }}-nuget-
44 | - name: Setup .NET 6.0
45 | uses: actions/setup-dotnet@v4
46 | with:
47 | dotnet-version: |
48 | 6.0.x
49 | - name: Build
50 | run: dotnet build --configuration DebugExcludeWPF
51 | - name: Test
52 | run: dotnet test --configuration DebugExcludeWPF
53 |
54 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet-publish.yml:
--------------------------------------------------------------------------------
1 | name: dotnet publish
2 |
3 | on:
4 | push:
5 | tags:
6 | - v*
7 |
8 | # See: https://docs.microsoft.com/ja-jp/dotnet/devops/dotnet-test-github-action
9 | # https://docs.microsoft.com/ja-jp/aspnet/core/host-and-deploy/visual-studio-publish-profiles?view=aspnetcore-6.0#folder-publish-example
10 | jobs:
11 | build:
12 | runs-on: windows-latest
13 | steps:
14 | - uses: actions/checkout@v4
15 | - name: Setup .NET 6.0
16 | uses: actions/setup-dotnet@v4
17 | with:
18 | dotnet-version: |
19 | 6.0.x
20 | - name: Publish AutoUpdater
21 | run: dotnet publish .\AutoUpdater\AutoUpdater.csproj /p:Configuration=Release /p:PublishProfile=FolderProfile
22 | - name: Publish WpfClient
23 | run: dotnet publish .\WpfClient\WpfClient.csproj /p:Configuration=Release /p:PublishProfile=FolderProfile
24 | - name: Collect package files
25 | run: |
26 | powershell Copy-Item -Path .\AutoUpdater\bin\Release\net6.0-windows\publish\P2PQuakeAutoUpdater.exe -Destination .\WpfClient\bin\Release\net6.0-windows10.0.18362.0\publish\
27 | - name: Package
28 | run: |
29 | powershell Move-Item .\WpfClient\bin\Release\net6.0-windows10.0.18362.0\publish .\P2PQuake_${{ github.ref_name }}; Compress-Archive -Path .\P2PQuake_${{ github.ref_name }} -DestinationPath .\P2PQuake_${{ github.ref_name }}.zip
30 | - name: Release
31 | uses: softprops/action-gh-release@v2
32 | with:
33 | files: P2PQuake_${{ github.ref_name }}.zip
34 |
--------------------------------------------------------------------------------
/AutoUpdater/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/AutoUpdater/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace AutoUpdater
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | protected override void OnStartup(StartupEventArgs e)
17 | {
18 | base.OnStartup(e);
19 |
20 | MainWindow = new MainWindow();
21 | MainWindow.Show();
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/AutoUpdater/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/AutoUpdater/AutoUpdater.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | net6.0-windows
6 | true
7 | Resources\icon.ico
8 | P2PQuakeAutoUpdater
9 | 3.5.3
10 | P2PQuake development team
11 | P2PQuake development team
12 | P2P地震情報 アップデーター
13 | https://www.p2pquake.net/
14 | https://github.com/p2pquake/epsp-peer-cs
15 | ja-JP
16 | 3.5.0.3
17 | 3.5.0.3
18 | AutoUpdater.Program
19 |
20 |
21 |
22 | embedded
23 | true
24 |
25 |
26 |
27 | DEBUG;TRACE
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | MSBuild:Compile
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/AutoUpdater/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
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 |
--------------------------------------------------------------------------------
/AutoUpdater/Program.cs:
--------------------------------------------------------------------------------
1 | using Sentry;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Windows;
9 |
10 | namespace AutoUpdater
11 | {
12 | public static class Program
13 | {
14 | /// 更新がないときに終了する
15 | public static bool silent = false;
16 |
17 | [STAThread]
18 | public static void Main(string[] args)
19 | {
20 | if (args.Length > 0 && args[0] == "silent")
21 | {
22 | silent = true;
23 | }
24 |
25 | InitSentry();
26 |
27 | App app = new();
28 | AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
29 | _ = app.Run();
30 | }
31 |
32 | private static void InitSentry()
33 | {
34 | SentrySdk.Init(o =>
35 | {
36 | o.Dsn = "https://812c520eddb245a69b331b802770c513@o1151228.ingest.sentry.io/6228133";
37 | #if DEBUG
38 | o.Environment = "debug";
39 | #else
40 | o.Environment = "release";
41 | #endif
42 | });
43 | }
44 |
45 | private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
46 | {
47 | SentrySdk.CaptureException((Exception)e.ExceptionObject);
48 |
49 | var dataContext = (MainWindowModel)App.Current.MainWindow.DataContext;
50 | if (dataContext != null)
51 | {
52 | dataContext.UpdatedResultMessage = "アップデートに失敗しました。";
53 | dataContext.UpdateStatus = UpdateStatus.Updated;
54 | }
55 |
56 | if (silent)
57 | {
58 | dataContext.UpdatedResultMessage = $"アップデートに失敗しました。\n\nエラー: {((Exception)e.ExceptionObject).Message}";
59 | return;
60 | }
61 |
62 | _ = MessageBox.Show($"エラーが発生したため、アップデートを中断しました。\n\nエラー: {((Exception)e.ExceptionObject).Message}", "P2P地震情報 アップデーター", MessageBoxButton.OK, MessageBoxImage.Error);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/AutoUpdater/Properties/PublishProfiles/FolderProfile.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Release
8 | Any CPU
9 | bin\Release\net6.0-windows\publish\
10 | FileSystem
11 | net6.0-windows
12 | win-x64
13 | false
14 | true
15 | false
16 |
17 |
--------------------------------------------------------------------------------
/AutoUpdater/Resources/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/AutoUpdater/Resources/icon.ico
--------------------------------------------------------------------------------
/AutoUpdater/Resources/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/AutoUpdater/Resources/icon.png
--------------------------------------------------------------------------------
/CLI/CLI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | CLI.Program
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/CLI/Command/MapCommand.cs:
--------------------------------------------------------------------------------
1 | using Map.Model;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.CommandLine;
6 | using System.CommandLine.Invocation;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 |
10 | namespace CLI.Command
11 | {
12 | public class MapCommand
13 | {
14 | public static System.CommandLine.Command Build()
15 | {
16 | var command = new System.CommandLine.Command(
17 | "map",
18 | "地図を生成します"
19 | )
20 | {
21 | EEWSubCommand.Build(),
22 | QuakeSubCommand.Build(),
23 | TsunamiSubCommand.Build(),
24 | UserquakeSubCommand.Build(),
25 | ServerSubCommand.Build(),
26 | };
27 |
28 | return command;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/CLI/Observers/DummyObserver.cs:
--------------------------------------------------------------------------------
1 | using Client.App;
2 | using Client.App.Userquake;
3 | using Client.Client;
4 | using Client.Peer;
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | namespace CLI.Observers
13 | {
14 | public class DummyObserver : IObserver
15 | {
16 | public MediatorContext MediatorContext { protected get; init; }
17 |
18 | public void Completed(object sender, OperationCompletedEventArgs e)
19 | {
20 | }
21 |
22 | public void ConnectionsChanged(object sender, EventArgs e)
23 | {
24 | }
25 |
26 | public void OnAreapeers(object sender, EventArgs e)
27 | {
28 | }
29 |
30 | public void OnEarthquake(object sender, EPSPQuakeEventArgs e)
31 | {
32 | }
33 |
34 | public void OnEEWTest(object sender, EPSPEEWTestEventArgs e)
35 | {
36 | }
37 |
38 | public void OnNewUserquakeEvaluation(object sender, UserquakeEvaluateEventArgs e)
39 | {
40 | }
41 |
42 | public void OnTsunami(object sender, EPSPTsunamiEventArgs e)
43 | {
44 | }
45 |
46 | public void OnUpdateUserquakeEvaluation(object sender, UserquakeEvaluateEventArgs e)
47 | {
48 | }
49 |
50 | public void OnUserquake(object sender, EPSPUserquakeEventArgs e)
51 | {
52 | }
53 |
54 | public void StateChanged(object sender, EventArgs e)
55 | {
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/CLI/Observers/GrpcObserver.cs:
--------------------------------------------------------------------------------
1 |
2 | using Client.App;
3 | using Client.App.Userquake;
4 | using Client.Client;
5 | using Client.Peer;
6 |
7 | using Microsoft.AspNetCore.Hosting;
8 | using Microsoft.Extensions.Hosting;
9 |
10 | using System;
11 |
12 | namespace CLI.Observers
13 | {
14 | ///
15 | /// gRPC サーバを建てるためのダミー Observer
16 | ///
17 | public class GrpcObserver : DummyObserver, IObserver
18 | {
19 | public void Build()
20 | {
21 | _ = new Grpc.Server(MediatorContext);
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/CLI/Observers/IObserver.cs:
--------------------------------------------------------------------------------
1 | using Client.App;
2 | using Client.App.Userquake;
3 | using Client.Client;
4 | using Client.Peer;
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | namespace CLI.Observers
13 | {
14 | public interface IObserver
15 | {
16 | MediatorContext MediatorContext { init; }
17 |
18 | void StateChanged(object sender, EventArgs e);
19 | void Completed(object sender, OperationCompletedEventArgs e);
20 | void ConnectionsChanged(object sender, EventArgs e);
21 | void OnEarthquake(object sender, EPSPQuakeEventArgs e);
22 | void OnTsunami(object sender, EPSPTsunamiEventArgs e);
23 | void OnAreapeers(object sender, EventArgs e);
24 | void OnEEWTest(object sender, EPSPEEWTestEventArgs e);
25 | void OnUserquake(object sender, EPSPUserquakeEventArgs e);
26 | void OnNewUserquakeEvaluation(object sender, UserquakeEvaluateEventArgs e);
27 | void OnUpdateUserquakeEvaluation(object sender, UserquakeEvaluateEventArgs e);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/CLI/Observers/ObserverFactory.cs:
--------------------------------------------------------------------------------
1 | using Client.App;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace CLI.Observers
10 | {
11 | public enum ObserverType
12 | {
13 | Dummy,
14 | Print,
15 | Grpc,
16 | }
17 |
18 | public static class ObserverFactory
19 | {
20 |
21 | public static IObserver CreateObserver(ObserverType type, MediatorContext m)
22 | {
23 | var r = GenerateObserver(type, m);
24 | m.StateChanged += r.StateChanged;
25 | m.Completed += r.Completed;
26 | m.ConnectionsChanged += r.ConnectionsChanged;
27 | m.OnEarthquake += r.OnEarthquake;
28 | m.OnTsunami += r.OnTsunami;
29 | m.OnAreapeers += r.OnAreapeers;
30 | m.OnEEWTest += r.OnEEWTest;
31 | m.OnUserquake += r.OnUserquake;
32 | m.OnNewUserquakeEvaluation += r.OnNewUserquakeEvaluation;
33 | m.OnUpdateUserquakeEvaluation += r.OnUpdateUserquakeEvaluation;
34 |
35 | return r;
36 | }
37 |
38 | private static IObserver GenerateObserver(ObserverType type, MediatorContext m)
39 | {
40 | return type switch
41 | {
42 | ObserverType.Dummy => new DummyObserver() { MediatorContext = m },
43 | ObserverType.Print => new PrintObserver() { MediatorContext = m },
44 | ObserverType.Grpc => GenerateGrpcObserver(m),
45 | _ => throw new ArgumentException($"Unknown receiver type: {type}"),
46 | };
47 | }
48 |
49 | // Note. 他の Observer でも似たようなことをしはじめたら IObserver に組み入れる
50 | private static GrpcObserver GenerateGrpcObserver(MediatorContext m)
51 | {
52 | var v = new GrpcObserver() { MediatorContext = m };
53 | v.Build();
54 | return v;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/CLI/Program.cs:
--------------------------------------------------------------------------------
1 | using CLI.Command;
2 | using CLI.Observers;
3 |
4 | using Client.App;
5 |
6 | using log4net.Config;
7 |
8 | using System;
9 | using System.CommandLine;
10 | using System.CommandLine.Invocation;
11 |
12 | namespace CLI
13 | {
14 | class Program
15 | {
16 | static int Main(string[] args)
17 | {
18 | var root = new RootCommand()
19 | {
20 | MapCommand.Build(),
21 | LoggerCommand.Build(),
22 | PublisherCommand.Build(),
23 | new System.CommandLine.Command("legacy", "これまでの Observers CLI を起動します")
24 | {
25 | Handler = CommandHandler.Create(() =>
26 | {
27 | GrcpMain();
28 | })
29 | },
30 | };
31 |
32 | return root.InvokeAsync(args).Result;
33 | }
34 |
35 | static void GrcpMain()
36 | {
37 | BasicConfigurator.Configure();
38 |
39 | var mc = new MediatorContext();
40 | var dr = ObserverFactory.CreateObserver(ObserverType.Dummy, mc);
41 | var pr = ObserverFactory.CreateObserver(ObserverType.Print, mc);
42 | var gr = ObserverFactory.CreateObserver(ObserverType.Grpc, mc);
43 |
44 | Console.ReadLine();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/CLI/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "CLI": {
4 | "commandName": "Project",
5 | "dotnetRunMessages": "true",
6 | "launchBrowser": false,
7 | "applicationUrl": "http://localhost:5000;https://localhost:5001",
8 | "environmentVariables": {
9 | "ASPNETCORE_ENVIRONMENT": "Development"
10 | }
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/CLI/Protos/operator.proto:
--------------------------------------------------------------------------------
1 | syntax = "proto3";
2 |
3 | option csharp_namespace = "CLI.Grpc.Services";
4 |
5 | package client;
6 | import "google/protobuf/empty.proto";
7 |
8 | service Operator {
9 | rpc GetConfiguration (GetConfigurationRequest) returns (GetConfigurationResponse);
10 | rpc SetConfiguration (SetConfigurationRequest) returns (SetConfigurationResponse);
11 |
12 | rpc GetState (GetStateRequest) returns (GetStateResponse);
13 |
14 | rpc Connect (google.protobuf.Empty) returns (BoolResponse);
15 | rpc Disconnect (google.protobuf.Empty) returns (BoolResponse);
16 | rpc SendUserquake (google.protobuf.Empty) returns (BoolResponse);
17 | }
18 |
19 | message BoolResponse {
20 | bool result = 1;
21 | }
22 |
23 | message GetConfigurationRequest {}
24 | message GetConfigurationResponse {
25 | ApplicationConfig config = 1;
26 | }
27 | message SetConfigurationRequest {
28 | ApplicationConfig config = 1;
29 | }
30 | message SetConfigurationResponse {
31 | bool result = 1;
32 | }
33 |
34 | message ApplicationConfig {
35 | int32 area_code = 1;
36 | bool port_open = 2;
37 | int32 port = 3;
38 | bool use_upnp = 4;
39 | int32 max_connections = 5;
40 | }
41 |
42 | message GetStateRequest {}
43 | message GetStateResponse {
44 | State state = 1;
45 | }
46 |
47 | message State {
48 | AppState app_state = 1;
49 | map areapeers = 2;
50 | int32 connections = 3;
51 | bool is_port_opened = 4;
52 | int32 peer_id = 5;
53 | bool has_key = 6;
54 | bool can_connect = 10;
55 | bool can_disconnect = 11;
56 | enum AppState {
57 | UNKNOWN = 0;
58 | DISCONNECTED = 1;
59 | CONNECTING = 2;
60 | CONNECTED = 3;
61 | MAINTENANCE = 4;
62 | DISCONNECTING = 5;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/CLI/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*",
10 | "Kestrel": {
11 | "EndpointDefaults": {
12 | "Protocols": "Http2"
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Client/App/IOperatable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Client.App
7 | {
8 | ///
9 | /// 接続制御が行うためのインタフェースです。
10 | ///
11 | public interface IOperatable
12 | {
13 | ///
14 | /// 接続処理を実行できる状態かどうかを表します。
15 | ///
16 | ///
17 | bool CanConnect { get; }
18 |
19 | ///
20 | /// 切断処理を実行できる状態かどうかを表します。
21 | ///
22 | ///
23 | bool CanDisconnect { get; }
24 |
25 | ///
26 | /// EPSPネットワークに接続します。
27 | ///
28 | ///
29 | bool Connect();
30 |
31 | ///
32 | /// EPSPネットワークから切断します。
33 | ///
34 | ///
35 | bool Disconnect();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Client/App/IPeerConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Client.App
8 | {
9 | ///
10 | /// EPSPピアの設定を行うインタフェースです。
11 | ///
12 | public interface IPeerConfig
13 | {
14 | /// 署名を検証するかどうか
15 | bool Verification { get; set; }
16 | /// 地震感知情報の多重発信を除去するかどうか
17 | bool UserquakeDuplicateRemove { get; set; }
18 |
19 | ///
20 | /// 地域コード(3桁)
21 | /// 0埋めのある本来の地域コードは を参照してください。
22 | ///
23 | int AreaCode { get; set; }
24 | /// 地域コード(3桁)
25 | string FormattedAreaCode { get; }
26 |
27 | /// ポート開放するかどうか
28 | bool IsPortOpen { get; set; }
29 | /// ポートをリッスンしているかどうか
30 | bool IsPortListening { get; }
31 | /// ポート番号
32 | int Port { get; set; }
33 |
34 | /// 最大接続数
35 | int MaxConnections { get; set; }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Client/App/IPeerState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Client.Client;
7 | using Client.Client.General;
8 |
9 | namespace Client.App
10 | {
11 | ///
12 | /// ピアの状態を表すインタフェースです。
13 | ///
14 | public interface IPeerState
15 | {
16 | /// ピアID
17 | int PeerId { get; }
18 | /// プロトコル時刻とシステム時刻の差
19 | TimeSpan TimeOffset { get; }
20 | /// 現在の接続数
21 | int Connections { get; }
22 | /// ポートが開放されているかどうか
23 | bool IsPortOpened { get; }
24 | /// 情報発信用の鍵情報
25 | KeyData Key { get; }
26 | /// 地域ピア数
27 | IDictionary AreaPeerDictionary { get; }
28 | /// 総ピア数
29 | int PeerCount { get; }
30 | /// プロトコル時刻を演算し、返します。
31 | DateTime CalcNowProtocolTime();
32 | }
33 |
34 | public interface IPeerStateForClient
35 | {
36 | int PeerId { get; set; }
37 |
38 | TimeSpan TimeOffset { get; set; }
39 |
40 | int Connections { get; }
41 |
42 | bool IsPortOpened { set; }
43 |
44 | KeyData Key { get; set; }
45 |
46 | IDictionary AreaPeerDictionary { get; set; }
47 |
48 | int PeerCount { get; }
49 |
50 | DateTime CalcNowProtocolTime();
51 | }
52 |
53 | interface IPeerStateForPeer
54 | {
55 | int PeerId { get; }
56 |
57 | TimeSpan TimeOffset { get; }
58 |
59 | KeyData Key { get; }
60 |
61 | IDictionary AreaPeerDictionary { get; set; }
62 |
63 | int PeerCount { get; }
64 |
65 | DateTime CalcNowProtocolTime();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Client/App/State/AbstractState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using Client.Client;
6 | using Client.Peer;
7 |
8 | namespace Client.App.State
9 | {
10 | public abstract class ReadonlyAbstractState
11 | {
12 | internal abstract bool CanConnect { get; }
13 | internal abstract bool CanDisconnect { get; }
14 | internal abstract bool CanMaintain { get; }
15 | }
16 |
17 | public abstract class AbstractState : ReadonlyAbstractState
18 | {
19 | internal virtual bool Connect(MediatorContext mediatorContext, IClientContext clientContext, IPeerContext peerContext)
20 | {
21 | throw new InvalidOperationException($"Cannot connect in {GetType().Name}");
22 | }
23 |
24 | internal virtual void Disconnect(MediatorContext mediatorContext, IClientContext clientContext, IPeerContext peerContext)
25 | {
26 | throw new InvalidOperationException($"Cannot disconnect in {GetType().Name}");
27 | }
28 |
29 | internal virtual bool Maintain(MediatorContext mediatorContext, IClientContext clientContext, IPeerContext peerContext)
30 | {
31 | throw new InvalidOperationException($"Cannot maintain in {GetType().Name}");
32 | }
33 |
34 | internal virtual void Completed(MediatorContext mediatorContext, IClientContext clientContext, IPeerContext peerContext, OperationCompletedEventArgs oce)
35 | {
36 | throw new NotImplementedException();
37 | }
38 |
39 | internal virtual void Abort(MediatorContext mediatorContext, IClientContext clientContext, IPeerContext peerContext)
40 | {
41 | throw new NotImplementedException();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Client/App/State/ConnectedState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using Client.Client;
6 | using Client.Peer;
7 |
8 | namespace Client.App.State
9 | {
10 | ///
11 | /// EPSPネットワークに接続済みの状態です。
12 | ///
13 | class ConnectedState : AbstractState
14 | {
15 | internal override bool CanConnect
16 | {
17 | get { return false; }
18 | }
19 |
20 | internal override bool CanDisconnect
21 | {
22 | get { return true; }
23 | }
24 |
25 | internal override bool CanMaintain
26 | {
27 | get { return true; }
28 | }
29 |
30 | internal override void Disconnect(MediatorContext mediatorContext, IClientContext clientContext, IPeerContext peerContext)
31 | {
32 | mediatorContext.State = new DisconnectingState();
33 | peerContext.DisconnectAll();
34 | clientContext.Part();
35 | }
36 |
37 | internal override bool Maintain(MediatorContext mediatorContext, IClientContext clientContext, IPeerContext peerContext)
38 | {
39 | mediatorContext.State = new MaintenanceState();
40 | return clientContext.Maintain();
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Client/App/State/DisconnectedState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using Client.Client;
6 | using Client.Peer;
7 |
8 | namespace Client.App.State
9 | {
10 | ///
11 | /// EPSPネットワークから切断された状態です。
12 | ///
13 | class DisconnectedState : AbstractState
14 | {
15 | internal override bool CanConnect
16 | {
17 | get { return true; }
18 | }
19 |
20 | internal override bool CanDisconnect
21 | {
22 | get { return false; }
23 | }
24 |
25 | internal override bool CanMaintain
26 | {
27 | get { return false; }
28 | }
29 |
30 | internal override bool Connect(MediatorContext mediatorContext, IClientContext clientContext, IPeerContext peerContext)
31 | {
32 | mediatorContext.State = new ConnectingState();
33 | return clientContext.Join();
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Client/App/State/DisconnectingState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using Client.Client;
6 | using Client.Client.General;
7 | using Client.Peer;
8 |
9 | namespace Client.App.State
10 | {
11 | ///
12 | /// EPSPネットワークからの切断を試みている状態です。
13 | ///
14 | class DisconnectingState : AbstractState
15 | {
16 | internal override bool CanConnect
17 | {
18 | get { return false; }
19 | }
20 |
21 | internal override bool CanDisconnect
22 | {
23 | get { return false; }
24 | }
25 |
26 | internal override bool CanMaintain
27 | {
28 | get { return false; }
29 | }
30 |
31 | internal override void Completed(MediatorContext mediatorContext, IClientContext clientContext, IPeerContext peerContext, OperationCompletedEventArgs oce)
32 | {
33 | if (oce.Result == ClientConst.OperationResult.Retryable)
34 | {
35 | mediatorContext.State = new ConnectedState();
36 | return;
37 | }
38 |
39 | mediatorContext.State = new DisconnectedState();
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Client/Application.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // このコードはツールによって生成されました。
4 | // ランタイム バージョン:4.0.30319.42000
5 | //
6 | // このファイルへの変更は、以下の状況下で不正な動作の原因になったり、
7 | // コードが再生成されるときに損失したりします。
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Client {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")]
16 | internal sealed partial class Application : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Application defaultInstance = ((Application)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Application())));
19 |
20 | public static Application Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 |
26 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
28 | [global::System.Configuration.DefaultSettingValueAttribute("p2pquake.ddo.jp:6910,www.p2pquake.net:6910,p2pquake.info:6910,p2pquake.xyz:6910")]
29 | public string servers {
30 | get {
31 | return ((string)(this["servers"]));
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Client/Application.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | p2pquake.ddo.jp:6910,www.p2pquake.net:6910,p2pquake.info:6910,p2pquake.xyz:6910
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Client/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | [assembly: InternalsVisibleTo("ClientTest")]
4 | [assembly: InternalsVisibleTo("DummyPeer")]
5 | [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
--------------------------------------------------------------------------------
/Client/Client.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 |
6 |
7 |
8 | embedded
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | True
25 | True
26 | Application.settings
27 |
28 |
29 |
30 |
31 |
32 | SettingsSingleFileGenerator
33 | application.Designer.cs
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Client/Client/General/KeyData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Client.Client.General
7 | {
8 | ///
9 | /// 鍵の情報をあらわすクラス
10 | ///
11 | public class KeyData
12 | {
13 | /// 秘密鍵
14 | public string PrivateKey { get; set; }
15 | /// 公開鍵
16 | public string PublicKey { get; set; }
17 | /// 有効期限
18 | public DateTime Expire { get; set; }
19 | /// 署名
20 | public string Signature { get; set; }
21 |
22 | public bool IsExpired(DateTime protocolTime)
23 | {
24 | return Expire < protocolTime;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Client/Client/General/ServerPoint.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Client.Client.General
8 | {
9 | class ServerPoint
10 | {
11 | public string Host { get; set; }
12 | public int Port { get; set; }
13 |
14 | public ServerPoint(string host, int port)
15 | {
16 | Host = host;
17 | Port = port;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Client/Client/IClientContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Client.App;
7 | using Client.Client.General;
8 | using Client.Client.State;
9 | using Client.Peer;
10 |
11 | namespace Client.Client
12 | {
13 | public enum ClientState
14 | {
15 | Disconnected,
16 | Connecting,
17 | Connected,
18 | Disconnecting,
19 | Maintaining,
20 | }
21 |
22 | public class OperationCompletedEventArgs : EventArgs
23 | {
24 | private ClientConst.OperationResult result;
25 | private ClientConst.ErrorCode errorCode;
26 |
27 | public ClientConst.OperationResult Result { get { return result; } }
28 | public ClientConst.ErrorCode ErrorCode { get { return errorCode; } }
29 |
30 | internal OperationCompletedEventArgs(ClientConst.OperationResult result, ClientConst.ErrorCode errorCode)
31 | {
32 | this.result = result;
33 | this.errorCode = errorCode;
34 | }
35 | }
36 |
37 | ///
38 | /// 上位クラスへ見せるClientContextインタフェース
39 | ///
40 | interface IClientContext
41 | {
42 | IPeerStateForClient PeerState { set; }
43 |
44 | IPeerConfig PeerConfig { set; }
45 |
46 | IPeerConnector PeerConnector { set; }
47 |
48 | AbstractState State { get; }
49 |
50 | event EventHandler StateChanged;
51 | event EventHandler OperationCompleted;
52 |
53 | ///
54 | /// 参加する
55 | ///
56 | ///
57 | bool Join();
58 |
59 | ///
60 | /// 参加終了する
61 | ///
62 | ///
63 | bool Part();
64 |
65 | ///
66 | /// 接続を維持する
67 | ///
68 | ///
69 | bool Maintain();
70 |
71 | ///
72 | /// 処理を強制的に中断する
73 | ///
74 | void Abort(ClientConst.ErrorCode errorCode);
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Client/Client/IClientContextForState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Client.App;
7 | using Client.Client.State;
8 | using Client.Peer;
9 |
10 | namespace Client.Client
11 | {
12 | interface IClientContextForState : IClientContext
13 | {
14 | new AbstractState State { set; }
15 | new IPeerConfig PeerConfig { get; }
16 | new IPeerStateForClient PeerState { get; }
17 | new IPeerConnector PeerConnector { get; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Client/Client/State/ConnectedState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Client.Client.General;
7 | using Client.Common.Net;
8 | using Client.Common.General;
9 |
10 | namespace Client.Client.State
11 | {
12 | ///
13 | /// 接続直後のフェーズ
14 | ///
15 | class ConnectedState : AbstractState
16 | {
17 | public ClientConst.ProcessType ProcessType { get; }
18 |
19 | public ConnectedState(ClientConst.ProcessType processType)
20 | {
21 | ProcessType = processType;
22 | }
23 |
24 | internal override void Process(IClientContextForState context, CRLFSocket socket)
25 | {
26 | Logger.GetLog().Debug("...再接続中かな?");
27 | // throw new NotSupportedException();
28 | }
29 |
30 | internal override void RequireAllowVersion(IClientContextForState context, CRLFSocket socket, Packet packet)
31 | {
32 | context.State = new NotifyProtocolVersionState(ProcessType);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Client/Client/State/EndConnectionState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Client.Client.General;
7 | using Client.Common.Net;
8 |
9 | namespace Client.Client.State
10 | {
11 | class EndConnectionState : AbstractState
12 | {
13 | private ClientConst.OperationResult operationResult;
14 | private ClientConst.ErrorCode errorCode;
15 |
16 | public EndConnectionState(ClientConst.OperationResult operationResult, ClientConst.ErrorCode errorCode)
17 | {
18 | this.operationResult = operationResult;
19 | this.errorCode = errorCode;
20 | }
21 |
22 | internal override void Process(IClientContextForState context, CRLFSocket socket)
23 | {
24 | socket.WriteLine("119 1");
25 | }
26 |
27 | internal override void EndConnection(IClientContextForState context, CRLFSocket socket, Packet packet)
28 | {
29 | socket.Close();
30 |
31 | context.State = new FinishedState(operationResult, errorCode);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Client/Client/State/FinishedState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Client.Common.Net;
7 | using Client.Client.General;
8 |
9 | namespace Client.Client.State
10 | {
11 | class FinishedState : AbstractState, IFinishedState
12 | {
13 | public ClientConst.OperationResult Result { get; private set; }
14 | public ClientConst.ErrorCode ErrorCode { get; private set; }
15 |
16 | public FinishedState(ClientConst.OperationResult result, ClientConst.ErrorCode errorCode)
17 | {
18 | Result = result;
19 | ErrorCode = errorCode;
20 | }
21 |
22 | internal override void Process(IClientContextForState context, CRLFSocket socket)
23 | {
24 | // 何もしない。
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Client/Client/State/IFinishedState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Client.Client.General;
7 |
8 | namespace Client.Client.State
9 | {
10 | interface IFinishedState
11 | {
12 | ClientConst.OperationResult Result { get; }
13 | ClientConst.ErrorCode ErrorCode { get; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Client/Client/State/NotifyProtocolVersionState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Client.Client.General;
7 | using Client.Common.Net;
8 | using Client.Common.General;
9 |
10 | namespace Client.Client.State
11 | {
12 | ///
13 | /// プロトコルバージョンの通知フェーズ
14 | ///
15 | class NotifyProtocolVersionState : AbstractState
16 | {
17 | ClientConst.ProcessType processType;
18 |
19 | public NotifyProtocolVersionState(ClientConst.ProcessType processType)
20 | {
21 | this.processType = processType;
22 | }
23 |
24 | internal override void Process(IClientContextForState context, CRLFSocket socket)
25 | {
26 | string[] datas = { Const.PROTOCOL_VERSION, Const.SOFTWARE_NAME, Const.SOFTWARE_VERSION };
27 | socket.WriteLine("131 1 " + string.Join(":", datas));
28 | }
29 |
30 |
31 | internal override void NoticeAllowVersion(IClientContextForState context, CRLFSocket socket, Packet packet)
32 | {
33 | string serverVersion = packet.Data[0];
34 |
35 | // TODO: サーバのプロトコルバージョンチェックしてない
36 |
37 | if (processType == ClientConst.ProcessType.Join)
38 | {
39 | context.State = new RequireTemporaryPeerIdState();
40 | }
41 | else if (processType == ClientConst.ProcessType.Maintain)
42 | {
43 | context.State = new PeerEchoState();
44 | }
45 | else if (processType == ClientConst.ProcessType.Part)
46 | {
47 | context.State = new RequirePartState();
48 | }
49 | else
50 | {
51 | throw new NotSupportedException();
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Client/Client/State/PeerEchoState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using Client.App;
6 |
7 | namespace Client.Client.State
8 | {
9 | class PeerEchoState : AbstractState
10 | {
11 | internal override void Process(IClientContextForState context, Common.Net.CRLFSocket socket)
12 | {
13 | IPeerStateForClient peerState = context.PeerState;
14 | string[] datas = { peerState.PeerId.ToString(), peerState.Connections.ToString() };
15 | socket.WriteLine("123 1 " + string.Join(":", datas));
16 | }
17 |
18 | internal override void AcceptedEcho(IClientContextForState context, Common.Net.CRLFSocket socket, Common.Net.Packet packet)
19 | {
20 | IPeerStateForClient peerState = context.PeerState;
21 | if (peerState.Key == null || peerState.Key.IsExpired(context.PeerState.CalcNowProtocolTime()))
22 | {
23 | context.State = new RequireReallocateKeyState();
24 | }
25 | else
26 | {
27 | // TODO: 接続数増加のしきい値が固定値になっている
28 | if (peerState.Connections <= 2)
29 | {
30 | context.State = new RequirePeerDataState(General.ClientConst.ProcessType.Maintain);
31 | }
32 | else
33 | {
34 | context.State = new RequireProtocolTimeState();
35 | }
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Client/Client/State/RequireAllocateKeyState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Globalization;
6 |
7 | using Client.Client.General;
8 | using Client.Common.Net;
9 |
10 | namespace Client.Client.State
11 | {
12 | class RequireAllocateKeyState : AbstractState
13 | {
14 | internal override void Process(IClientContextForState context, CRLFSocket socket)
15 | {
16 | socket.WriteLine("117 1 " + context.PeerState.PeerId);
17 | }
18 |
19 | internal override void AllocateKey(IClientContextForState context, CRLFSocket socket, Packet packet)
20 | {
21 | context.PeerState.Key = CreateKeyData(packet);
22 | context.State = new RequireAreaPeersState();
23 | }
24 |
25 | internal override void KeyCantAllocateError(IClientContextForState context, CRLFSocket socket, Packet packet)
26 | {
27 | context.State = new RequireAreaPeersState();
28 | }
29 |
30 | public KeyData CreateKeyData(Packet packet)
31 | {
32 | KeyData key = new KeyData();
33 | key.PrivateKey = packet.Data[0];
34 | key.PublicKey = packet.Data[1];
35 | key.Expire = DateTime.ParseExact(packet.Data[2], "yyyy/MM/dd HH-mm-ss", DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None);
36 | key.Signature = packet.Data[3];
37 |
38 | return key;
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Client/Client/State/RequireAreaPeersState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Client.Common.Net;
7 |
8 | namespace Client.Client.State
9 | {
10 | class RequireAreaPeersState : AbstractState
11 | {
12 | internal override void Process(IClientContextForState context, CRLFSocket socket)
13 | {
14 | socket.WriteLine("127 1");
15 | }
16 |
17 | internal override void NoticeAreaPeers(IClientContextForState context, CRLFSocket socket, Packet packet)
18 | {
19 | context.PeerState.AreaPeerDictionary = packet.Data[0].Split(';').ToDictionary(v => v.Split(',')[0], v => int.Parse(v.Split(',')[1]));
20 | context.State = new RequireProtocolTimeState();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Client/Client/State/RequirePartState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using Client.App;
6 | using Client.Client.General;
7 | using Client.Common.Net;
8 |
9 | namespace Client.Client.State
10 | {
11 | class RequirePartState : AbstractState
12 | {
13 | internal override void Process(IClientContextForState context, CRLFSocket socket)
14 | {
15 | IPeerStateForClient peerState = context.PeerState;
16 | string[] datas = { peerState.PeerId.ToString(), (peerState.Key == null ? "Unknown" : peerState.Key.PublicKey) };
17 |
18 | socket.WriteLine("128 1 " + string.Join(":", datas));
19 | }
20 |
21 | internal override void AcceptedPart(IClientContextForState context, CRLFSocket socket, Packet packet)
22 | {
23 | context.State = new EndConnectionState(ClientConst.OperationResult.Successful, ClientConst.ErrorCode.SUCCESSFUL);
24 | }
25 |
26 | internal override void AddressChangedError(IClientContextForState context, CRLFSocket socket, Packet packet)
27 | {
28 | context.State = new EndConnectionState(ClientConst.OperationResult.Restartable, ClientConst.ErrorCode.RETURNED_ADDRESS_CHANGED);
29 | }
30 |
31 | internal override void IncorrectRequestError(IClientContextForState context, CRLFSocket socket, Packet packet)
32 | {
33 | context.State = new EndConnectionState(ClientConst.OperationResult.Restartable, ClientConst.ErrorCode.RETURNED_INVALID_REQUEST);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Client/Client/State/RequirePeerDataState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Client.Client.General;
7 | using Client.Common.General;
8 | using Client.Common.Net;
9 |
10 | namespace Client.Client.State
11 | {
12 | ///
13 | /// ピアデータ要求のフェーズ
14 | ///
15 | class RequirePeerDataState : AbstractState
16 | {
17 | ClientConst.ProcessType processType;
18 |
19 | public RequirePeerDataState(ClientConst.ProcessType processType)
20 | {
21 | this.processType = processType;
22 | }
23 |
24 | internal override void Process(IClientContextForState context, CRLFSocket socket)
25 | {
26 | if (context.PeerState.PeerId <= 0)
27 | throw new InvalidOperationException("ピアIDが設定されていません。");
28 |
29 | socket.WriteLine("115 1 " + context.PeerState.PeerId);
30 | }
31 |
32 | internal override void ReceiveJoiningPeerData(IClientContextForState context, CRLFSocket socket, Packet packet)
33 | {
34 | IList peerList = new List();
35 |
36 | if (packet.Data != null)
37 | {
38 | foreach (string peer in packet.Data)
39 | {
40 | string[] peerData = peer.Split(new char[] { ',' });
41 | peerList.Add(new PeerData(peerData[0], int.Parse(peerData[1]), int.Parse(peerData[2])));
42 | }
43 | }
44 |
45 | int[] connectedPeerIds = context.PeerConnector.Connect(peerList.ToArray());
46 |
47 | socket.WriteLine("155 1 " + string.Join(":", Array.ConvertAll(connectedPeerIds, delegate(int v) { return v.ToString(); })));
48 |
49 | if (processType == ClientConst.ProcessType.Join)
50 | {
51 | context.State = new RequirePeerIdState();
52 | }
53 | else if (processType == ClientConst.ProcessType.Maintain)
54 | {
55 | context.State = new RequireProtocolTimeState();
56 | }
57 | else
58 | {
59 | throw new NotImplementedException();
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Client/Client/State/RequirePeerIdState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using Client.App;
6 | using Client.Common.Net;
7 |
8 | namespace Client.Client.State
9 | {
10 | class RequirePeerIdState : AbstractState
11 | {
12 | internal override void Process(IClientContextForState context, CRLFSocket socket)
13 | {
14 | IPeerStateForClient peerState = context.PeerState;
15 | string[] datas = { peerState.PeerId.ToString(), context.PeerConfig.Port.ToString(), context.PeerConfig.FormattedAreaCode, peerState.Connections.ToString(), context.PeerConfig.MaxConnections.ToString() };
16 |
17 | socket.WriteLine("116 1 " + string.Join(":", datas));
18 | }
19 |
20 | internal override void AllocatePeerId(IClientContextForState context, CRLFSocket socket, Packet packet)
21 | {
22 | // TODO: 鍵の取得は任意だが、必ず実施してしまっている
23 | context.State = new RequireAllocateKeyState();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Client/Client/State/RequirePortScanState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Client.Common.Net;
7 |
8 | namespace Client.Client.State
9 | {
10 | ///
11 | /// ポート開放チェック要求フェーズ
12 | ///
13 | class RequirePortScanState : AbstractState
14 | {
15 | internal override void Process(IClientContextForState context, CRLFSocket socket)
16 | {
17 | string[] datas = { context.PeerState.PeerId.ToString(), context.PeerConfig.Port.ToString() };
18 | socket.WriteLine("114 1 " + string.Join(":", datas));
19 | }
20 |
21 | internal override void ReceivePortCheckResult(IClientContextForState context, CRLFSocket socket, Packet packet)
22 | {
23 | context.PeerState.IsPortOpened = (packet.Data[0] == "1");
24 |
25 | context.State = new RequirePeerDataState(General.ClientConst.ProcessType.Join);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Client/Client/State/RequireProtocolTimeState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.Linq;
5 | using System.Text;
6 |
7 | using Client.Client.General;
8 | using Client.Common.Net;
9 |
10 | namespace Client.Client.State
11 | {
12 | class RequireProtocolTimeState : AbstractState
13 | {
14 | internal override void Process(IClientContextForState context, CRLFSocket socket)
15 | {
16 | socket.WriteLine("118 1");
17 | }
18 |
19 | internal override void ReceiveProtocolTime(IClientContextForState context, CRLFSocket socket, Packet packet)
20 | {
21 | DateTime protocolTime = DateTime.ParseExact(packet.Data[0], "yyyy/MM/dd HH-mm-ss", DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None);
22 | context.PeerState.TimeOffset = protocolTime - DateTime.Now;
23 |
24 | context.State = new EndConnectionState(ClientConst.OperationResult.Successful, ClientConst.ErrorCode.SUCCESSFUL);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Client/Client/State/RequireReallocateKeyState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Client.Common.Net;
7 |
8 | namespace Client.Client.State
9 | {
10 | class RequireReallocateKeyState : AbstractState
11 | {
12 | internal override void Process(IClientContextForState context, Common.Net.CRLFSocket socket)
13 | {
14 | string[] datas = { context.PeerState.PeerId.ToString(), "Unknown" };
15 | if (context.PeerState.Key != null)
16 | {
17 | // FIXME: PrivateKeyに値入っているっけ?
18 | datas[1] = context.PeerState.Key.PrivateKey;
19 | }
20 |
21 | socket.WriteLine("124 1 " + string.Join(":", datas));
22 | }
23 |
24 | internal override void ReAllocateKey(IClientContextForState context, CRLFSocket socket, Packet packet)
25 | {
26 | RequireAllocateKeyState allocateKeyState = new RequireAllocateKeyState();
27 | context.PeerState.Key = allocateKeyState.CreateKeyData(packet);
28 |
29 | ChangeState(context);
30 | }
31 |
32 | internal override void KeyCantAllocateError(IClientContextForState context, CRLFSocket socket, Packet packet)
33 | {
34 | ChangeState(context);
35 | }
36 |
37 | private void ChangeState(IClientContextForState context)
38 | {
39 | if (context.PeerState.Connections <= 2)
40 | {
41 | context.State = new RequirePeerDataState(General.ClientConst.ProcessType.Maintain);
42 | }
43 | else
44 | {
45 | context.State = new RequireProtocolTimeState();
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Client/Client/State/RequireTemporaryPeerIdState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Client.Common.Net;
7 |
8 | namespace Client.Client.State
9 | {
10 | ///
11 | /// ピアIDの暫定割り当てフェーズ
12 | ///
13 | class RequireTemporaryPeerIdState : AbstractState
14 | {
15 | internal override void Process(IClientContextForState context, CRLFSocket socket)
16 | {
17 | socket.WriteLine("113 1");
18 | }
19 |
20 | internal override void AllocateTemporaryPeerId(IClientContextForState context, CRLFSocket socket, Packet packet)
21 | {
22 | string peerId = packet.Data[0];
23 | context.PeerState.PeerId = int.Parse(peerId);
24 |
25 | if (context.PeerConfig.IsPortOpen && context.PeerConfig.IsPortListening)
26 | {
27 | context.State = new RequirePortScanState();
28 | return;
29 | }
30 |
31 | context.PeerState.IsPortOpened = false;
32 | context.State = new RequirePeerDataState(General.ClientConst.ProcessType.Join);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Client/Common/General/Const.cs:
--------------------------------------------------------------------------------
1 | namespace Client.Common.General
2 | {
3 | class Const
4 | {
5 | public static readonly string PROTOCOL_VERSION = "0.38";
6 | public static readonly string SOFTWARE_NAME = "P2PQ_SharpClient";
7 | // TODO: SOFTWARE_VERSIONを自動生成したい
8 | public static readonly string SOFTWARE_VERSION = "compatible_0.35.012";
9 | public static readonly double ALLOW_PROTOCOL_VERSION = 0.30;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Client/Common/General/Logger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using System.Diagnostics;
7 | using System.Reflection;
8 | using System.Security;
9 | using log4net;
10 |
11 | namespace Client.Common.General
12 | {
13 | static class Logger
14 | {
15 | [DynamicSecurityMethod]
16 | public static ILog GetLog()
17 | {
18 | const int callerFrameIndex = 1;
19 | StackFrame callerFrame = new StackFrame(callerFrameIndex);
20 | MethodBase callerMethod = callerFrame.GetMethod();
21 | return LogManager.GetLogger (Assembly.GetCallingAssembly(), callerMethod.DeclaringType);
22 | }
23 | }
24 | }
25 |
26 | namespace System.Security
27 | {
28 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
29 | internal sealed class DynamicSecurityMethodAttribute : Attribute
30 | {
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Client/Common/General/PeerData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Client.Common.General
7 | {
8 | public class PeerData
9 | {
10 | private string address;
11 | private int port;
12 | private int peerId;
13 |
14 | public string Address { get { return address; } }
15 | public int Port { get { return port; } }
16 | public int PeerId { get { return peerId; } set { peerId = value; } }
17 |
18 | public PeerData(string address, int port, int peerId)
19 | {
20 | this.address = address;
21 | this.port = port;
22 | this.peerId = peerId;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Client/Common/Net/AsyncListener.cs:
--------------------------------------------------------------------------------
1 | using Client.Common.General;
2 |
3 | using System;
4 | using System.Net;
5 | using System.Net.Sockets;
6 |
7 | namespace Client.Common.Net
8 | {
9 | public class AcceptEventArgs : EventArgs
10 | {
11 | public Socket Socket { get; set; }
12 | }
13 |
14 | public class AsyncListener
15 | {
16 | bool interrupt;
17 | int port;
18 |
19 | TcpListener tcpListener;
20 | public event EventHandler Accept = delegate (object s, AcceptEventArgs e) { };
21 |
22 | public AsyncListener(int port)
23 | {
24 | this.port = port;
25 | this.interrupt = false;
26 |
27 | Logger.GetLog().Debug("インスタンス初期化 (ポート: " + port + ")");
28 | }
29 |
30 | public void Start()
31 | {
32 | tcpListener = new TcpListener(IPAddress.Any, port);
33 | tcpListener.Start();
34 | AcceptInfinite();
35 |
36 | Logger.GetLog().Debug("リッスン (IPv4 TCP ポート: " + port + ")");
37 | }
38 |
39 | async private void AcceptInfinite()
40 | {
41 | while (!interrupt)
42 | {
43 | try
44 | {
45 | Socket socket = await tcpListener.AcceptSocketAsync();
46 | Logger.GetLog().Debug("接続受け入れ: " + socket.RemoteEndPoint.ToString());
47 |
48 | var acceptEventArgs = new AcceptEventArgs();
49 | acceptEventArgs.Socket = socket;
50 | Accept(this, acceptEventArgs);
51 | }
52 | catch (ObjectDisposedException)
53 | {
54 | Logger.GetLog().Debug("リッスン中断");
55 | }
56 | catch (SocketException ex)
57 | {
58 | Logger.GetLog().Warn("対ピア接続受け入れ時にエラーが発生しました。無視します。", ex);
59 | }
60 | }
61 |
62 | Logger.GetLog().Debug("リッスン処理終了");
63 | }
64 |
65 | public void Stop()
66 | {
67 | Logger.GetLog().Debug("リッスン中断要求");
68 |
69 | interrupt = true;
70 | tcpListener.Stop();
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Client/Common/Net/ISocket.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Client.Common.Net
10 | {
11 | public interface ISocket
12 | {
13 | bool Connected { get; }
14 | EndPoint RemoteEndPoint { get; }
15 |
16 | void Shutdown(SocketShutdown both);
17 | void Close();
18 | IAsyncResult BeginConnect(string host, int port, AsyncCallback asyncCallback, ISocket iSocket);
19 | void EndConnect(IAsyncResult ar);
20 | void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback asyncCallback, ISocket iSocket);
21 | void Send(byte[] buffer);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Client/Common/Net/SocketAdapter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Client.Common.Net
10 | {
11 | public class SocketAdapter : ISocket
12 | {
13 | private Socket socket;
14 |
15 | public SocketAdapter(Socket socket)
16 | {
17 | this.socket = socket;
18 | }
19 |
20 | public virtual bool Connected { get { return socket.Connected; } }
21 | public virtual EndPoint RemoteEndPoint { get { return socket.RemoteEndPoint; } }
22 |
23 | public virtual IAsyncResult BeginConnect(string host, int port, AsyncCallback asyncCallback, ISocket iSocket)
24 | {
25 | return socket.BeginConnect(host, port, asyncCallback, socket);
26 | }
27 |
28 | public virtual void BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback asyncCallback, ISocket iSocket)
29 | {
30 | socket.BeginReceive(buffer, offset, size, socketFlags, asyncCallback, socket);
31 | }
32 |
33 | public virtual void Close()
34 | {
35 | socket.Close();
36 | }
37 |
38 | public virtual void EndConnect(IAsyncResult ar)
39 | {
40 | socket.EndConnect(ar);
41 | }
42 |
43 | public virtual void Send(byte[] buffer)
44 | {
45 | socket.Send(buffer);
46 | }
47 |
48 | public virtual void Shutdown(SocketShutdown both)
49 | {
50 | socket.Shutdown(both);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Client/Common/Net/UPnP/UPnPUtil.cs:
--------------------------------------------------------------------------------
1 | using Mono.Nat;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Net;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 |
11 | namespace Client.Common.Net.UPnP
12 | {
13 | public class UPnPUtil
14 | {
15 | public static bool OpenPort(int port)
16 | {
17 | bool completed = false;
18 | // 別 Task で走らせて 3 秒だけは待つ。
19 | Task.Run(() =>
20 | {
21 | NatUtility.DeviceFound += (s, e) =>
22 | {
23 | var device = e.Device;
24 | try
25 | {
26 | device.CreatePortMap(new Mapping(Protocol.Tcp, port, port));
27 | } catch (Exception)
28 | {
29 | // 開放に失敗しても何もしない.
30 | }
31 | completed = true;
32 | };
33 | NatUtility.StartDiscovery(NatProtocol.Upnp);
34 | Thread.Sleep(3000);
35 | NatUtility.StopDiscovery();
36 | }).Wait();
37 | return completed;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Client/Peer/General/Code.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Client.Peer.General
8 | {
9 | class Code
10 | {
11 | public static readonly int EARTHQUAKE = 551;
12 | public static readonly int TSUNAMI = 552;
13 | public static readonly int USERQUAKE = 555;
14 | public static readonly int AREAPEERS = 561;
15 |
16 | public static readonly int PEER_PING = 611;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Client/Peer/IPeerConnector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Client.Common.General;
7 |
8 | namespace Client.Peer
9 | {
10 | ///
11 | /// 上位クラス・隣接クラスへ見せるPeerConnectorインタフェース
12 | ///
13 | public interface IPeerConnector
14 | {
15 | ///
16 | /// ピア接続数が変化したことを通知します。
17 | ///
18 | event EventHandler ConnectionsChanged;
19 |
20 | ///
21 | /// 指定したピアへの接続を試行します。
22 | ///
23 | /// ピア情報
24 | /// 接続したピアのピアID
25 | int[] Connect(PeerData[] peers);
26 |
27 | /// 接続数
28 | int Connections { get; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Client/Peer/Manager/DuplicateRemover.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | using Client.Common.Net;
7 |
8 | namespace Client.Peer.Manager
9 | {
10 | class DuplicateRemover
11 | {
12 | private static readonly int DUPLICATE_CAPACITY = 10000;
13 | private List duplicateList;
14 |
15 | public DuplicateRemover()
16 | {
17 | duplicateList = new List(DUPLICATE_CAPACITY);
18 | }
19 |
20 | public bool isDuplicate(Packet packet)
21 | {
22 | string data = $"{packet.Code}:{string.Join(":", packet.Data)}";
23 |
24 | lock (duplicateList)
25 | {
26 | if (duplicateList.Contains(data))
27 | {
28 | return true;
29 | }
30 | else
31 | {
32 | if (duplicateList.Count >= DUPLICATE_CAPACITY)
33 | {
34 | duplicateList.RemoveAt(0);
35 | }
36 |
37 | duplicateList.Add(data);
38 | return false;
39 | }
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Client/Peer/Manager/NetworkInquiryManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Client.Peer.Manager
8 | {
9 | class InquiryData
10 | {
11 | public string peerId;
12 | public string uniqueValue;
13 | public Peer peer;
14 | }
15 |
16 | class NetworkInquiryManager
17 | {
18 | private static readonly int CAPACITY = 100;
19 | private List inquiryList;
20 |
21 | public NetworkInquiryManager()
22 | {
23 | inquiryList = new List(CAPACITY);
24 | }
25 |
26 | public Peer FindPeer(string peerId, string uniqueValue)
27 | {
28 | var result = inquiryList.Where(e => (e.peerId == peerId && e.uniqueValue == uniqueValue));
29 | if (result.Count() > 0)
30 | {
31 | return result.First().peer;
32 | }
33 | return null;
34 | }
35 |
36 | public void Add(string peerId, string uniqueValue, Peer peer)
37 | {
38 | var inquiryData = new InquiryData() { peerId = peerId, uniqueValue = uniqueValue, peer = peer };
39 | if (inquiryList.Count >= CAPACITY)
40 | {
41 | inquiryList.RemoveAt(0);
42 | }
43 | inquiryList.Add(inquiryData);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Client/Peer/Manager/UserquakeDuplicateRemover.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics.CodeAnalysis;
4 | using System.IO.Pipes;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Client.Peer.Manager
10 | {
11 | class UserquakeDuplicateRemover
12 | {
13 | private static readonly int ALLOW_MIN_INTERVAL_SECONDS = 300;
14 | private static readonly int CLEANUP_INTERVAL_COUNT = 512;
15 |
16 | private Dictionary userquakes;
17 | private Func protocolTime;
18 | private int cleanupCount = 0;
19 |
20 | public UserquakeDuplicateRemover(Func protocolTime)
21 | {
22 | this.userquakes = new Dictionary();
23 | this.protocolTime = protocolTime;
24 | }
25 |
26 | public bool IsDuplicate(string publicKey)
27 | {
28 | var now = protocolTime();
29 |
30 | lock(userquakes)
31 | {
32 | if (!userquakes.ContainsKey(publicKey))
33 | {
34 | PurgeExpired();
35 | userquakes[publicKey] = now;
36 | return false;
37 | }
38 |
39 | if (now.Subtract(userquakes[publicKey]).TotalSeconds >= ALLOW_MIN_INTERVAL_SECONDS)
40 | {
41 | userquakes[publicKey] = now;
42 | return false;
43 | }
44 |
45 | return true;
46 | }
47 | }
48 |
49 | private void PurgeExpired()
50 | {
51 | cleanupCount += 1;
52 | if (cleanupCount < CLEANUP_INTERVAL_COUNT)
53 | {
54 | return;
55 | }
56 | cleanupCount = 0;
57 |
58 | var now = protocolTime();
59 | lock (userquakes)
60 | {
61 | var expiredUserquakes = userquakes.Where(e => now.Subtract(e.Value).TotalSeconds >= ALLOW_MIN_INTERVAL_SECONDS);
62 | foreach (var expiredUserquake in expiredUserquakes)
63 | {
64 | userquakes.Remove(expiredUserquake.Key);
65 | }
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/Client/Peer/State/GeneralState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace Client.Peer.State
7 | {
8 | class GeneralState : AbstractState
9 | {
10 |
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/ClientTest/App/MaintainTimerTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Text;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using Client.App;
9 | using Client.App.State;
10 | using Client.Client;
11 | using Client.Client.General;
12 |
13 | using Moq;
14 | using NUnit.Framework;
15 |
16 | namespace ClientTest.App
17 | {
18 | [TestFixture]
19 | class MaintainTimerTest
20 | {
21 | [TestCase]
22 | public void LongTimeConnectingTest()
23 | {
24 | var mediatorContext = new MediatorContext();
25 |
26 | var maintainTimerField = mediatorContext.GetType().GetField("maintainTimer", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);
27 | var timer = (MaintainTimer)maintainTimerField.GetValue(mediatorContext);
28 | var intervalField = timer.GetType().GetField("maintainInterval", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Instance);
29 | intervalField.SetValue(timer, 1000);
30 |
31 | var field = mediatorContext.GetType().GetField("clientContext", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Instance);
32 | var clientContextMock = new Mock();
33 | field.SetValue(mediatorContext, clientContextMock.Object);
34 |
35 | // 本来は DisconnectedState への遷移を確認したいが、難しくやむを得ずモックで確認している
36 | var isCalled = false;
37 | clientContextMock.Setup(m => m.Abort(It.IsAny())).Callback(() => { isCalled = true; });
38 |
39 | mediatorContext.StateChanged += (s, e) => { };
40 | mediatorContext.Completed += (s, e) => { };
41 | mediatorContext.ConnectionsChanged += (s, e) => { };
42 |
43 | mediatorContext.Connect();
44 |
45 | int waitSeconds = 120;
46 | while (waitSeconds-- > 0 && !isCalled)
47 | {
48 | Thread.Sleep(1000);
49 | }
50 |
51 | Assert.IsTrue(isCalled);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/ClientTest/ClientTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | Library
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | PreserveNewest
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/ClientTest/Common/Net/CRLFSocketTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net.Sockets;
5 | using System.Reflection;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Client.Common.Net;
9 | using Moq;
10 | using NUnit.Framework;
11 |
12 | namespace ClientTest.Common.Net
13 | {
14 | [TestFixture]
15 | class CRLFSocketTest
16 | {
17 | [TestCase]
18 | public void MoqMockingTest()
19 | {
20 | var crlfSocket = new CRLFSocket();
21 | var field = crlfSocket.GetType().GetField("socket", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Instance);
22 |
23 | Assert.AreEqual(ConnectionState.Closed, crlfSocket.State);
24 |
25 | var mockSocket = new Mock();
26 | mockSocket.SetupGet(x => x.Connected).Returns(true);
27 | field.SetValue(crlfSocket, mockSocket.Object);
28 |
29 | Assert.AreEqual(ConnectionState.Connected, crlfSocket.State);
30 | }
31 |
32 | [TestCase]
33 | public void DisposedExceptionTest()
34 | {
35 | var crlfSocket = new CRLFSocket();
36 | var field = crlfSocket.GetType().GetField("socket", BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Instance);
37 |
38 | var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
39 | var mockSocket = new Mock(socket) { CallBase = true };
40 | mockSocket.SetupGet(x => x.Connected).Returns(true);
41 | field.SetValue(crlfSocket, mockSocket.Object);
42 |
43 | socket.Dispose();
44 | Assert.IsFalse(crlfSocket.WriteLine("611 1"));
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/ClientTest/Common/Net/UPnP/UPnPUtilTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Client.Common.Net.UPnP;
7 | using NUnit.Framework;
8 |
9 | namespace ClientTest.Common.Net.UPnP
10 | {
11 | [TestFixture]
12 | class UPnPUtilTest
13 | {
14 | [Test]
15 | public void OpenPort()
16 | {
17 | UPnPUtil.OpenPort(6910);
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/ClientTest/Peer/Manager/NetworkInquiryManagerTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Client.Peer.Manager;
7 | using NUnit.Framework;
8 |
9 | namespace ClientTest.Peer.Manager
10 | {
11 | [TestFixture]
12 | class NetworkInquiryManagerTest
13 | {
14 | NetworkInquiryManager networkInquiryManager;
15 |
16 | [SetUp]
17 | public void SetUp()
18 | {
19 | networkInquiryManager = new NetworkInquiryManager();
20 | }
21 |
22 | [Test]
23 | public void NullTest()
24 | {
25 | Assert.IsNull(networkInquiryManager.FindPeer(null, null));
26 | }
27 |
28 | [Test]
29 | public void EmptyTest()
30 | {
31 | Assert.IsNull(networkInquiryManager.FindPeer(string.Empty, string.Empty));
32 | }
33 |
34 | [Test]
35 | public void SimpleFindTest()
36 | {
37 | var peer = new Client.Peer.Manager.Peer(null);
38 | networkInquiryManager.Add("100", "200", peer);
39 | Assert.AreSame(peer, networkInquiryManager.FindPeer("100", "200"));
40 | }
41 |
42 | [Test]
43 | public void CapacityBoundaryTest()
44 | {
45 | var peer = new Client.Peer.Manager.Peer(null);
46 | networkInquiryManager.Add("100", "200", peer);
47 |
48 | foreach (int i in Enumerable.Range(0, 99))
49 | {
50 | networkInquiryManager.Add("200", "300", new Client.Peer.Manager.Peer(null));
51 | }
52 | Assert.AreSame(peer, networkInquiryManager.FindPeer("100", "200"));
53 |
54 | networkInquiryManager.Add("200", "300", new Client.Peer.Manager.Peer(null));
55 | Assert.IsNull(networkInquiryManager.FindPeer("100", "200"));
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/ClientTest/SampleTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using NUnit.Framework;
7 |
8 | namespace ClientTest
9 | {
10 | [TestFixture]
11 | public class SampleTest
12 | {
13 | [TestCase]
14 | public void SampleTest_001()
15 | {
16 | Assert.Pass("NUnit works!");
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/DummyPeer/DummyPeer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/DummyPeer/Peer/Context.cs:
--------------------------------------------------------------------------------
1 | using Client.App;
2 | using Client.Common.General;
3 | using Client.Common.Net;
4 | using Client.Peer;
5 | using Client.Peer.Manager;
6 |
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 |
13 | namespace DummyPeer.Peer
14 | {
15 | ///
16 | /// Client.Peer.Context をベースに、単独動作を可能とした Context
17 | ///
18 | class Context
19 | {
20 | private PeerManager peerManager;
21 | private AsyncListener asyncListener;
22 |
23 | public Context()
24 | {
25 | peerManager = new PeerManager();
26 | peerManager.PeerId += () => 9999;
27 | peerManager.ProtocolTime += () => DateTime.Now;
28 | peerManager.PeerCount += () => 2;
29 | peerManager.ConnectionsChanged += (s, e) => { };
30 | peerManager.OnAreapeers += (s, e) => { };
31 | peerManager.OnEarthquake += (s, e) => { };
32 | peerManager.OnTsunami += (s, e) => { };
33 | peerManager.OnEEWTest += (s, e) => { };
34 | peerManager.OnUserquake += (s, e) => { };
35 | }
36 |
37 | public bool Listen(int port)
38 | {
39 | EndListen();
40 |
41 | asyncListener = new AsyncListener(port);
42 | asyncListener.Accept += AsyncListener_Accept;
43 | asyncListener.Start();
44 |
45 | return true;
46 | }
47 |
48 | private void AsyncListener_Accept(object sender, AcceptEventArgs e)
49 | {
50 | peerManager.AddFromSocket(e.Socket);
51 | }
52 |
53 | public bool Connect(PeerData peer)
54 | {
55 | return peerManager.Connect(peer);
56 | }
57 |
58 | public void SendAll(Packet packet)
59 | {
60 | peerManager.Send(packet);
61 | }
62 |
63 | public void DisconnectAll()
64 | {
65 | peerManager.DisconnectAll();
66 | }
67 |
68 | public bool EndListen()
69 | {
70 | if (asyncListener == null)
71 | {
72 | return false;
73 | }
74 |
75 | asyncListener.Stop();
76 | return true;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/DummyPeer/Program.cs:
--------------------------------------------------------------------------------
1 | using DummyPeer.Peer;
2 |
3 | using System;
4 | using System.CommandLine;
5 | using System.CommandLine.Invocation;
6 | using System.Security.Cryptography;
7 |
8 | namespace DummyPeer
9 | {
10 | class RootOptions
11 | {
12 | public int Port { get; set; }
13 | }
14 |
15 | class Program
16 | {
17 | static int Main(string[] args)
18 | {
19 | var root = new RootCommand()
20 | {
21 | new Option(new[]{ "-p", "--port" }, () => 6910, "listen port")
22 | };
23 | root.Handler = CommandHandler.Create(RootHandler);
24 |
25 | return root.InvokeAsync(args).Result;
26 | }
27 |
28 | private static void RootHandler(RootOptions options)
29 | {
30 | var context = new Context();
31 | context.Listen(options.Port);
32 | var randomSender = new RandomSender(context);
33 | Console.WriteLine($"listen port: {options.Port}");
34 | Console.WriteLine("Press enter to exit");
35 | Console.ReadLine();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/DummyPeer/README.md:
--------------------------------------------------------------------------------
1 | # DummyPeer
2 |
3 | 動作確認用ダミーピア実装
4 |
5 | ## 機能
6 |
7 | - 過去情報のランダム配信
8 |
9 | ## 注意点
10 |
11 | - プロトコル時刻
12 | - コンピュータの時計を使用します
13 | - 署名(公開鍵暗号)
14 | - 期限内の有効な署名を付与します
15 | - ただし、サーバー保証用公開鍵・ピア保証用公開鍵は実環境と異なります
16 |
17 | ### サーバー保証用公開鍵
18 |
19 | PKCS #8 (DER) 形式:
20 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDB+t0YTWlu3FFiwTb05u2bHWJRpCQJeAzhia6pWJ5BqsVIXgG7zeiHu4cFWrKME7fHQsjlihjnhtaksEtkmnbODUHnNi26FStSSpyo8ex0FZDfXtoQ9VB0m6UxdrGznpzfO9PWbpC0iSoCAyeqILLcDDbuBv5xY6+0D35kQx74kQIDAQAB
21 |
22 | ### ピア保証用公開鍵
23 |
24 | PKCS #8 (DER) 形式:
25 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDImNYMTSCn3CWtQ8uq9qbU5WGQcdtAorXGD7/3ahK+CMkngJpkMdfUtuPRbMfDvbt/szNU38BYmMMQWK1OC/iav4Nac7fWHuXMYprCeyULFpQXmyLWySTPUyHs/zYw067wbO751RuV6bAmjH2TlRv8Yb1UY/atZRuYSiu58Z4cCQIDAQAB
26 |
--------------------------------------------------------------------------------
/DummyPeer/ServerCrypto/DataSigner.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DummyPeer.ServerCrypto
9 | {
10 | public static class DataSigner
11 | {
12 | static DataSigner()
13 | {
14 | Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
15 | }
16 |
17 | public static string SignInformation(string data)
18 | {
19 | // 署名用データ生成
20 | byte[] signData = Encoding.GetEncoding(932).GetBytes(data);
21 | return SignInformation(signData);
22 | }
23 |
24 | public static string SignInformation(byte[] data)
25 | {
26 | SHA1CryptoServiceProvider sha1Provider = new SHA1CryptoServiceProvider();
27 | byte[] sha1SignData = sha1Provider.ComputeHash(data);
28 |
29 | // 署名生成
30 | RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider();
31 | rsaProvider.ImportParameters(KeyDefine.ServerVerificationKey);
32 |
33 | RSAPKCS1SignatureFormatter pkcsFormatter = new RSAPKCS1SignatureFormatter(rsaProvider);
34 | pkcsFormatter.SetHashAlgorithm("SHA1");
35 |
36 | byte[] sign = pkcsFormatter.CreateSignature(sha1SignData);
37 | return Convert.ToBase64String(sign, Base64FormattingOptions.None);
38 | }
39 |
40 | public static string SignServerData(string data, DateTime expire)
41 | {
42 | // "EPSP日時 + Shift-JISバイト列のMD5"のバイト列を署名する
43 |
44 | // MD5導出
45 | byte[] dataByteArray = Encoding.GetEncoding(932).GetBytes(data);
46 | MD5CryptoServiceProvider md5Provider = new MD5CryptoServiceProvider();
47 | byte[] dataMd5 = md5Provider.ComputeHash(dataByteArray);
48 |
49 | // EPSP日時
50 | string expireStr = expire.ToString("yyyy/MM/dd HH-mm-ss");
51 | byte[] expireByteArray = Encoding.ASCII.GetBytes(expireStr);
52 |
53 | // 結合して署名
54 | byte[] signData = expireByteArray.Concat(dataMd5).ToArray();
55 | return SignInformation(signData);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/DummyPeer/ServerCrypto/PacketSigner.cs:
--------------------------------------------------------------------------------
1 | using Client.Common.Net;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace DummyPeer.ServerCrypto
10 | {
11 | public class PacketSigner
12 | {
13 | public static Packet Sign(Packet packet)
14 | {
15 | var expire = DateTime.Now.AddMinutes(5);
16 | var data = "";
17 |
18 | if (packet.Code == 551)
19 | {
20 | data = packet.Data[0] + packet.Data[1];
21 | }
22 | if (packet.Code == 552)
23 | {
24 | data = packet.Data[0];
25 | }
26 | if (packet.Code == 561)
27 | {
28 | data = packet.Data[0];
29 | }
30 |
31 | var signature = DataSigner.SignServerData(data, expire);
32 |
33 | packet.Data = new string[] { signature, expire.ToString("yyyy/MM/dd HH-mm-ss") }.Concat(packet.Data).ToArray();
34 |
35 | return packet;
36 | }
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/DummyPeer/ServerCrypto/PeerKey.cs:
--------------------------------------------------------------------------------
1 | using Asn1PKCS.Encoder;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Security.Cryptography;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace DummyPeer.ServerCrypto
11 | {
12 | public class PeerKey
13 | {
14 | public DateTime Expire { get; set; }
15 | public string KeySignature { get; set; }
16 | public RSAParameters RSAParam { get; set; }
17 |
18 | ///
19 | /// PKCS #8 RSAPublicKey
20 | ///
21 | public string PublicKey
22 | {
23 | get { return PKCS8DEREncoder.EncodePublicKeyToBase64(RSAParam); }
24 | }
25 |
26 | ///
27 | /// PKCS #8 RSAPublicKey
28 | ///
29 | public byte[] PublicKeyBytes
30 | {
31 | get { return PKCS8DEREncoder.EncodePublicKey(RSAParam); }
32 | }
33 |
34 | ///
35 | /// PKCS #8 RSAPrivateKey
36 | ///
37 | public string PrivateKey
38 | {
39 | get { return PKCS8DEREncoder.EncodePrivateKeyToBase64(RSAParam); }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/IPC/IPC.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace IPC
4 | {
5 | public static class Const
6 | {
7 | public const string Name = "p2pquake-ipc";
8 | }
9 |
10 | public record Message(Method Method);
11 |
12 | public enum Method
13 | {
14 | Show,
15 | Exit,
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/IPC/IPC.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 |
6 |
7 |
8 | embedded
9 | true
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/JsonApi/BasicData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Text.Json.Serialization;
6 | using System.Threading.Tasks;
7 |
8 | namespace JsonApi
9 | {
10 | [JsonConverter(typeof(JsonApiConverterWithTypeDiscriminator))]
11 | public class BasicData
12 | {
13 | public string Id { get; set; }
14 | public int Code { get; set; }
15 | public string Time { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/JsonApi/Client.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net.Http;
5 | using System.Text;
6 | using System.Text.Json;
7 | using System.Threading.Tasks;
8 |
9 | namespace JsonApi
10 | {
11 | public enum Code
12 | {
13 | Earthquake = 551,
14 | Tsunami = 552,
15 | [Obsolete("代わりに EEW を使用してください。")]
16 | EEWTest = 554,
17 | EEW = 556,
18 | UserquakeEvaluation = 9611,
19 | }
20 |
21 | public class Client
22 | {
23 | static readonly HttpClientHandler handler = new HttpClientHandler()
24 | {
25 | AutomaticDecompression = System.Net.DecompressionMethods.All,
26 | };
27 | static readonly HttpClient client = new(handler);
28 |
29 | public async static Task Get(int limit = 100, int offset = 0, params Code[] codes)
30 | {
31 | var response = await client.GetAsync($"https://api.p2pquake.net/v2/history?limit={limit}&offset={offset}{(codes.Length > 0 ? "&" : "")}{string.Join('&', codes.Select(e => $"codes={(int)e}"))}");
32 | response.EnsureSuccessStatusCode();
33 | string body = await response.Content.ReadAsStringAsync();
34 |
35 | var deserializeOptions = new JsonSerializerOptions()
36 | {
37 | PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
38 | };
39 | var items = JsonSerializer.Deserialize(body, deserializeOptions);
40 |
41 | return items;
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/JsonApi/EEW.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace JsonApi
8 | {
9 | public class EEW : BasicData
10 | {
11 | public bool Cancelled { get; set; }
12 | public EEWEarthquake Earthquake { get; set; }
13 | public EEWIssue Issue { get; set; }
14 | public EEWArea[] Areas { get; set; }
15 | }
16 |
17 | public class EEWEarthquake
18 | {
19 | public string OriginTime { get; set; }
20 | public string ArrivalTime { get; set; }
21 | public string Condition { get; set; }
22 | public EEWHypocenter Hypocenter { get; set; }
23 | }
24 |
25 | public class EEWIssue
26 | {
27 | public string Time { get; set; }
28 | public string EventId { get; set; }
29 | public string Serial { get; set; }
30 | }
31 |
32 | public class EEWHypocenter
33 | {
34 | public string Name { get; set; }
35 | public string ReduceName { get; set; }
36 | public double Latitude { get; set; }
37 | public double Longitude { get; set; }
38 | public int Depth { get; set; }
39 | public double Magnitude { get; set; }
40 | }
41 |
42 | public class EEWArea
43 | {
44 | public string Pref { get; set; }
45 | public string Name { get; set; }
46 | public int ScaleFrom { get; set; }
47 | public int ScaleTo { get; set; }
48 | public string KindCode { get; set; }
49 | public string ArrivalTime { get; set; }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/JsonApi/EEWDetection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace JsonApi
8 | {
9 | public class EEWDetection : BasicData
10 | {
11 | public string Type { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/JsonApi/JMAQuake.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace JsonApi
8 | {
9 |
10 | public class JMAQuake : BasicData
11 | {
12 | public QuakeIssue Issue { get; set; }
13 | public Earthquake Earthquake { get; set; }
14 | public Point[] Points { get; set; }
15 | public Comments Comments { get; set; }
16 | }
17 |
18 | public class QuakeIssue
19 | {
20 | public string Correct { get; set; }
21 | public string Source { get; set; }
22 | public string Time { get; set; }
23 | public string Type { get; set; }
24 | }
25 |
26 | public class Earthquake
27 | {
28 | public string Time { get; set; }
29 | public Hypocenter Hypocenter { get; set; }
30 | public int MaxScale { get; set; }
31 | public string DomesticTsunami { get; set; }
32 | public string ForeignTsunami { get; set; }
33 | }
34 |
35 | public class Hypocenter
36 | {
37 | public string Name { get; set; }
38 | public float Latitude { get; set; }
39 | public float Longitude { get; set; }
40 | public int Depth { get; set; }
41 | public float Magnitude { get; set; }
42 | }
43 |
44 | public class Point
45 | {
46 | public string Pref { get; set; }
47 | public string Addr { get; set; }
48 | public bool IsArea { get; set; }
49 | public int Scale { get; set; }
50 | }
51 |
52 | public class Comments
53 | {
54 | public string FreeFormComment { get; set; }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/JsonApi/JMATsunami.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace JsonApi
8 | {
9 | public class JMATsunami : BasicData
10 | {
11 | public bool Cancelled { get; set; }
12 | public TsunamiIssue Issue { get; set; }
13 | public Area[] Areas { get; set; }
14 | }
15 |
16 | public class TsunamiIssue
17 | {
18 | public string Source { get; set; }
19 | public string Time { get; set; }
20 | public string Type { get; set; }
21 | }
22 |
23 | public class Area
24 | {
25 | public string Grade { get; set; }
26 | public bool Immediate { get; set; }
27 | public string Name { get; set; }
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/JsonApi/JsonApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Library
5 | net6.0
6 |
7 |
8 |
9 |
10 |
11 | embedded
12 | true
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/JsonApi/JsonApiConverterWithTypeDiscriminator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Text.Json;
6 | using System.Text.Json.Serialization;
7 | using System.Threading.Tasks;
8 |
9 | namespace JsonApi
10 | {
11 | public class JsonApiConverterWithTypeDiscriminator : JsonConverter
12 | {
13 | public override BasicData Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
14 | {
15 | if (reader.TokenType != JsonTokenType.StartObject)
16 | {
17 | throw new JsonException();
18 | }
19 |
20 | using (var document = JsonDocument.ParseValue(ref reader))
21 | {
22 | if (!document.RootElement.TryGetProperty("code", out var codeProperty))
23 | {
24 | throw new JsonException();
25 | }
26 |
27 | var code = codeProperty.GetInt32();
28 | var rawText = document.RootElement.GetRawText();
29 |
30 | return code switch
31 | {
32 | 551 => JsonSerializer.Deserialize(rawText, options),
33 | 552 => JsonSerializer.Deserialize(rawText, options),
34 | 554 => JsonSerializer.Deserialize(rawText, options),
35 | 556 => JsonSerializer.Deserialize(rawText, options),
36 | 9611 => JsonSerializer.Deserialize(rawText, options),
37 | _ => JsonSerializer.Deserialize(rawText, options),
38 | };
39 | }
40 | }
41 |
42 | public override void Write(Utf8JsonWriter writer, BasicData value, JsonSerializerOptions options)
43 | {
44 | throw new NotImplementedException();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/JsonApi/UnknownData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace JsonApi
8 | {
9 | public class UnknownData : BasicData
10 | {
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/JsonApi/UserquakeEvaluation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Text.Json.Serialization;
6 | using System.Threading.Tasks;
7 |
8 | namespace JsonApi
9 | {
10 | public class UserquakeEvaluation : BasicData
11 | {
12 | public int Count { get; set; }
13 | public float Confidence { get; set; }
14 | [JsonPropertyName("started_at")]
15 | public string StartedAt { get; set; }
16 | [JsonPropertyName("updated_at")]
17 | public string UpdatedAt { get; set; }
18 | [JsonPropertyName("area_confidences")]
19 | public IDictionary AreaConfidences { get; set; }
20 | }
21 |
22 | public class AreaConfidence
23 | {
24 | public float Confidence { get; set; }
25 | public int Count { get; set; }
26 | public string Display { get; set; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 P2PQuake development team
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/LambdaMetricsCollector/Function.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/LambdaMetricsCollector/Function.cs
--------------------------------------------------------------------------------
/LambdaMetricsCollector/LambdaMetricsCollector.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | true
5 | Lambda
6 |
7 | true
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/LambdaMetricsCollector/Properties/PublishProfiles/FolderProfile.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Release
8 | Any CPU
9 | bin\Release\net6.0\publish\linux-x64\
10 | FileSystem
11 | net6.0
12 | linux-x64
13 | false
14 | False
15 |
16 |
--------------------------------------------------------------------------------
/LambdaMetricsCollector/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "Mock Lambda Test Tool": {
4 | "commandName": "Executable",
5 | "commandLineArgs": "--port 5050",
6 | "workingDirectory": ".\\bin\\$(Configuration)\\net6.0",
7 | "executablePath": "%USERPROFILE%\\.dotnet\\tools\\dotnet-lambda-test-tool-6.0.exe"
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/LegacyPluginSupporter/LegacyPluginSupporter.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 | Exe
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/LegacyPluginSupporter/Net/Packet.cs:
--------------------------------------------------------------------------------
1 | namespace LegacyPluginSupporter.Net
2 | {
3 | public class Packet
4 | {
5 | public string Code { get; set; }
6 | public string[] Data { get; set; }
7 |
8 | ///
9 | /// プラグインからの通信をパースします(プラグインへの通信はパースできません)
10 | ///
11 | public static Packet Parse(string line)
12 | {
13 | Packet packet = new();
14 | if (packet.parse(line))
15 | {
16 | return packet;
17 | }
18 | else
19 | {
20 | throw new FormatException();
21 | }
22 | }
23 |
24 | private bool parse(string packet)
25 | {
26 | // 改行は削除
27 | packet = packet.Replace("\r", "").Replace("\n", "");
28 | string[] datas = packet.Split(new char[] { ' ' }, 2);
29 |
30 | // 初期値
31 | Code = "";
32 | Data = null;
33 |
34 | if (datas.Length <= 0 || datas.Length >= 3)
35 | {
36 | return false;
37 | }
38 | else
39 | {
40 | Code = datas[0];
41 | if (datas.Length >= 2)
42 | {
43 | Data = new string[] { datas[1] };
44 | }
45 | return true;
46 | }
47 | }
48 |
49 | public string ToPacketString()
50 | {
51 | string packet;
52 | packet = Code;
53 |
54 | if (Data != null && Data.Length > 0)
55 | {
56 | packet += " " + string.Join(":", Data);
57 | }
58 |
59 | return packet;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/LegacyPluginSupporter/Plugin.cs:
--------------------------------------------------------------------------------
1 | using LegacyPluginSupporter.Net;
2 |
3 | namespace LegacyPluginSupporter
4 | {
5 | public class PluginReadLineEventArgs : EventArgs
6 | {
7 | public Packet packet;
8 | }
9 |
10 | public class Plugin
11 | {
12 | public string PluginName { get; private set; } = "";
13 | public DateTime ConnectedAt { get; init; }
14 |
15 | private readonly CRLFSocket socket;
16 | private readonly string serverName;
17 |
18 | public event EventHandler OnClosed = (s, e) => { };
19 | public event EventHandler OnNameNotified = (s, e) => { };
20 | public event EventHandler OnReadLine = (s, e) => { };
21 |
22 | internal Plugin(CRLFSocket socket, string serverName)
23 | {
24 | this.socket = socket;
25 | this.serverName = serverName;
26 | socket.Closed += Socket_Closed;
27 | socket.ReadLine += Socket_ReadLine;
28 | }
29 |
30 | public void BeginReceive()
31 | {
32 | socket.BeginReceive();
33 | }
34 |
35 | public void Disconnect()
36 | {
37 | socket.Close();
38 | }
39 |
40 | public void Send(Packet packet)
41 | {
42 | socket.WriteLine(packet.ToPacketString());
43 | }
44 |
45 | private void Socket_Closed(object? sender, EventArgs e)
46 | {
47 | OnClosed(this, EventArgs.Empty);
48 | }
49 |
50 | private void Socket_ReadLine(object? sender, ReadLineEventArgs e)
51 | {
52 | if (e.packet.Code == "JOIN")
53 | {
54 | PluginName = e.packet.Data[0];
55 | Send(new Packet() { Code = "SVER", Data = new string[] { serverName } });
56 | OnNameNotified(this, EventArgs.Empty);
57 | return;
58 | }
59 |
60 | OnReadLine(this, new PluginReadLineEventArgs()
61 | {
62 | packet = e.packet
63 | });
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/LegacyPluginSupporter/Program.cs:
--------------------------------------------------------------------------------
1 | namespace LegacyPluginSupporter
2 | {
3 | class Program
4 | {
5 | static int Main(string[] args)
6 | {
7 | var manager = new Manager("プラグイン接続テストツール");
8 | manager.OnNameNotified += (s, e) => { Console.WriteLine($"Name notified from {((Plugin)s).PluginName}"); };
9 | manager.OnExitRequest += (s, e) => { Console.WriteLine($"Exit request from {((Plugin)s).PluginName}"); };
10 | manager.OnUserquakeRequest += (s, e) => { Console.WriteLine($"Userquake request from {((Plugin)s).PluginName}"); };
11 |
12 | manager.Listen();
13 | while (true)
14 | {
15 | Console.ReadLine();
16 | foreach (var plugin in manager.PluginList)
17 | {
18 | Console.WriteLine($"プラグイン: {plugin.PluginName} ({plugin.GetHashCode()})");
19 | manager.RequestOption(plugin);
20 | }
21 | Console.WriteLine("----");
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/LegacyPluginSupporterTest/LegacyPluginSupporterTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 | false
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LegacyPluginSupporterTest/Usings.cs:
--------------------------------------------------------------------------------
1 | global using NUnit.Framework;
--------------------------------------------------------------------------------
/Map/Map.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | Library
6 |
7 |
8 |
9 | embedded
10 | true
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | True
25 | True
26 | FontResource.resx
27 |
28 |
29 | True
30 | True
31 | ImageResource.resx
32 |
33 |
34 | True
35 | True
36 | PointResource.resx
37 |
38 |
39 |
40 |
41 |
42 | ResXFileCodeGenerator
43 | FontResource.Designer.cs
44 |
45 |
46 | ResXFileCodeGenerator
47 | ImageResource.Designer.cs
48 |
49 |
50 | ResXFileCodeGenerator
51 | PointResource.Designer.cs
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/Map/Model/AbstractDrawer.cs:
--------------------------------------------------------------------------------
1 | using SixLabors.ImageSharp;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Map.Model
10 | {
11 | ///
12 | /// 座標範囲
13 | ///
14 | /// 左端の経度 (0~180: 東経、 180~360: 西経 (180~0 に対応))
15 | /// 上端の緯度 (90~0: 北緯、 -0~-90: 南緯)
16 | /// 右端の経度 (0~180: 東経、 180~360: 西経 (180~0 に対応))
17 | /// 下端の緯度 (90~0: 北緯、 -0~-90: 南緯)
18 | public record LTRBCoordinate(double LeftLongitude, double TopLatitude, double RightLongitude, double BottomLatitude);
19 |
20 | public abstract class AbstractDrawer
21 | {
22 | public Image Image { get; init; }
23 | public LTRBCoordinate LTRB { get; init; }
24 | public bool IsMercator { get; init; }
25 |
26 | public abstract void Draw();
27 | public abstract LTRBCoordinate CalcDrawLTRB();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Map/Model/GeoJson.cs:
--------------------------------------------------------------------------------
1 | namespace Map.Model
2 | {
3 | public class GeoJson
4 | {
5 | public string type { get; set; }
6 | public Feature[] features { get; set; }
7 | }
8 |
9 | public class Feature
10 | {
11 | public string type { get; set; }
12 | public Geometry geometry { get; set; }
13 | public Properties properties { get; set; }
14 | }
15 |
16 | public class Geometry
17 | {
18 | public string type { get; set; }
19 | public float[][][][] coordinates { get; set; }
20 | }
21 |
22 | public class Properties
23 | {
24 | public string code { get; set; }
25 | public bool islandBold { get; set; }
26 | public object name { get; set; }
27 | }
28 |
29 | // XXX: できれば共通化したい。
30 | public class MultiLineGeoJson
31 | {
32 | public string type { get; set; }
33 | public MultiLineFeature[] features { get; set; }
34 | }
35 |
36 | public class MultiLineFeature
37 | {
38 | public string type { get; set; }
39 | public MultiLineGeometry geometry { get; set; }
40 | public MultiLineProperties properties { get; set; }
41 | }
42 |
43 | public class MultiLineGeometry
44 | {
45 | public string type { get; set; }
46 | public float[][][] coordinates { get; set; }
47 | }
48 |
49 | public class MultiLineProperties
50 | {
51 | public string code { get; set; }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Map/Model/HypocenterDrawer.cs:
--------------------------------------------------------------------------------
1 | using SixLabors.ImageSharp;
2 | using SixLabors.ImageSharp.Drawing;
3 | using SixLabors.ImageSharp.Drawing.Processing;
4 | using SixLabors.ImageSharp.Processing;
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | namespace Map.Model
13 | {
14 | class HypocenterDrawer : AbstractDrawer
15 | {
16 | public double Latitude { get; init; }
17 | public double Longitude { get; init; }
18 |
19 | public override LTRBCoordinate CalcDrawLTRB()
20 | {
21 | return new LTRBCoordinate(Longitude, Latitude, Longitude, Latitude);
22 | }
23 |
24 | static readonly List lineParams = new List() { -1, 1 };
25 |
26 | public override void Draw()
27 | {
28 | var transformation = new Transformation
29 | {
30 | ImageWidth = Image.Width,
31 | ImageHeight = Image.Height,
32 | IsMercator = IsMercator,
33 | LTRBCoordinate = LTRB,
34 | };
35 | var pos = transformation.Geo2Pixel(new GeoCoordinate(Latitude, Longitude));
36 |
37 | var size = 6;
38 | var thickness = 2;
39 |
40 | lineParams.ForEach(v =>
41 | {
42 | var path = new Path(new LinearLineSegment(
43 | new SixLabors.ImageSharp.PointF(pos.X - size, pos.Y - (size * v)),
44 | new SixLabors.ImageSharp.PointF(pos.X + size, pos.Y + (size * v))
45 | ));
46 | Image.Mutate(x => x.Draw(Color.Red, thickness, path));
47 | });
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Map/Model/ObservationAreas.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Text.Json;
4 |
5 | namespace Map.Model
6 | {
7 | public record ObservationArea(string Prefecture, string Name, GeoCoordinate[][] Coordinates);
8 |
9 | public class ObservationAreas
10 | {
11 | public static ObservationAreas Instance { get; private set; } = new();
12 |
13 | private readonly IReadOnlyDictionary observationAreas;
14 |
15 | private ObservationAreas()
16 | {
17 | Dictionary areas = new();
18 |
19 | var jsons = JsonSerializer.Deserialize(PointResource.AreaGeoJsons, new JsonSerializerOptions { IncludeFields = true });
20 | var areaCodes = PointResource.EarthquakeAreaCodes.Replace("\r", "").Split('\n').Where((line) => line.Length > 0).Select((line) => line.Split(',')).ToDictionary(e => e[0], e => e[1]);
21 |
22 | foreach (var feature in jsons.features)
23 | {
24 | var name = areaCodes[feature.properties.code];
25 | var area = new ObservationArea(
26 | null,
27 | name,
28 | feature.geometry.coordinates
29 | .Select(e => e[0].Select(e => new GeoCoordinate(e[1], e[0])).ToArray()).ToArray()
30 | );
31 |
32 | // 既に存在してたら足す
33 | if (areas.ContainsKey(name))
34 | {
35 | areas[name] = new ObservationArea(
36 | null,
37 | name,
38 | areas[name].Coordinates.Concat(area.Coordinates).ToArray()
39 | );
40 | } else
41 | {
42 | areas.Add(name, area);
43 | }
44 |
45 | }
46 |
47 | observationAreas = areas;
48 | }
49 |
50 | public ObservationArea GetArea(string name)
51 | {
52 | if (!observationAreas.ContainsKey(name))
53 | {
54 | return null;
55 | }
56 |
57 | return observationAreas[name];
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Map/Model/StationNameShorter.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 |
3 | namespace Map.Model
4 | {
5 | public class StationNameShorter
6 | {
7 | public static readonly Regex ShortenPattern = new(@"^((?:余市町|田村市|玉村町|東村山市|武蔵村山市|羽村市|十日町市|上市町|大町市|名古屋中村区|大阪堺市.+?区|下市町|大村市|野々市市|四日市市|廿日市市|大町町|.+?[市区町村]))", RegexOptions.Compiled);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Map/Model/TsunamiAreas.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Text.Json;
4 |
5 | namespace Map.Model
6 | {
7 | public record TsunamiArea(string Name, GeoCoordinate[][] Coordinates);
8 |
9 | public class TsunamiAreas
10 | {
11 | public static TsunamiAreas Instance { get; private set; } = new();
12 |
13 | private readonly IReadOnlyDictionary tsunamiAreas;
14 |
15 | private TsunamiAreas()
16 | {
17 | Dictionary areas = new();
18 |
19 | var jsons = JsonSerializer.Deserialize(PointResource.TsunamiAreaGeoJsons, new JsonSerializerOptions { IncludeFields = true });
20 | var areaCodes = PointResource.TsunamiAreaCodes.Replace("\r", "").Split('\n').Where((line) => line.Length > 0).Select((line) => line.Split(',')).ToDictionary(e => e[0], e => e[1]);
21 |
22 | foreach (var feature in jsons.features)
23 | {
24 | var name = areaCodes[feature.properties.code];
25 | var area = new TsunamiArea(
26 | name,
27 | feature.geometry.coordinates
28 | .Select(e => e.Select(e => new GeoCoordinate(e[1], e[0])).ToArray()).ToArray()
29 | );
30 |
31 | // 既に存在してたら足す
32 | if (areas.ContainsKey(name))
33 | {
34 | areas[name] = new TsunamiArea(
35 | name,
36 | areas[name].Coordinates.Concat(area.Coordinates).ToArray()
37 | );
38 | }
39 | else
40 | {
41 | areas.Add(name, area);
42 | }
43 |
44 | }
45 |
46 | tsunamiAreas = areas;
47 | }
48 |
49 | public TsunamiArea GetArea(string name)
50 | {
51 | if (!tsunamiAreas.ContainsKey(name))
52 | {
53 | return null;
54 | }
55 |
56 | return tsunamiAreas[name];
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Map/Resources/Fonts/RobotoMono-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Fonts/RobotoMono-Bold.ttf
--------------------------------------------------------------------------------
/Map/Resources/Fonts/RobotoMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Fonts/RobotoMono-Regular.ttf
--------------------------------------------------------------------------------
/Map/Resources/Images/confidence.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/confidence.xcf
--------------------------------------------------------------------------------
/Map/Resources/Images/confidence_A.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/confidence_A.png
--------------------------------------------------------------------------------
/Map/Resources/Images/confidence_B.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/confidence_B.png
--------------------------------------------------------------------------------
/Map/Resources/Images/confidence_C.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/confidence_C.png
--------------------------------------------------------------------------------
/Map/Resources/Images/confidence_D.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/confidence_D.png
--------------------------------------------------------------------------------
/Map/Resources/Images/confidence_E.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/confidence_E.png
--------------------------------------------------------------------------------
/Map/Resources/Images/confidence_F.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/confidence_F.png
--------------------------------------------------------------------------------
/Map/Resources/Images/description.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/description.png
--------------------------------------------------------------------------------
/Map/Resources/Images/quake_note.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/quake_note.png
--------------------------------------------------------------------------------
/Map/Resources/Images/scale.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/scale.xcf
--------------------------------------------------------------------------------
/Map/Resources/Images/scaleMap.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/scaleMap.xcf
--------------------------------------------------------------------------------
/Map/Resources/Images/scale_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/scale_10.png
--------------------------------------------------------------------------------
/Map/Resources/Images/scale_20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/scale_20.png
--------------------------------------------------------------------------------
/Map/Resources/Images/scale_30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/scale_30.png
--------------------------------------------------------------------------------
/Map/Resources/Images/scale_40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/scale_40.png
--------------------------------------------------------------------------------
/Map/Resources/Images/scale_45.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/scale_45.png
--------------------------------------------------------------------------------
/Map/Resources/Images/scale_46.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/scale_46.png
--------------------------------------------------------------------------------
/Map/Resources/Images/scale_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/scale_50.png
--------------------------------------------------------------------------------
/Map/Resources/Images/scale_55.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/scale_55.png
--------------------------------------------------------------------------------
/Map/Resources/Images/scale_60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/scale_60.png
--------------------------------------------------------------------------------
/Map/Resources/Images/scale_70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/scale_70.png
--------------------------------------------------------------------------------
/Map/Resources/Images/tsunami_note_advisory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/tsunami_note_advisory.png
--------------------------------------------------------------------------------
/Map/Resources/Images/tsunami_note_majorwarning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/tsunami_note_majorwarning.png
--------------------------------------------------------------------------------
/Map/Resources/Images/tsunami_note_warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/tsunami_note_warning.png
--------------------------------------------------------------------------------
/Map/Resources/Images/userquake_note.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Images/userquake_note.png
--------------------------------------------------------------------------------
/Map/Resources/Maps/LICENSE.TXT:
--------------------------------------------------------------------------------
1 | $LastChangedDate: 2013-11-24 09:26:07 -1000 (Sun, 24 Nov 2013) $
2 | $Revision: 594 $
3 |
4 | As of GSHHG 2.2.2, GSHHG is distributed under the GNU Lesser General Public
5 | License (LGPL) version 3 or later. Copies of the The GNU General Public
6 | License (GPL) and the GNU Lesser General Public License (LGPL) are
7 | distributed along with the sources. Refer to the files COPYINGv3 and
8 | COPYING.LESSERv3.
9 |
10 | Permission to use, copy, modify, and distribute (with no more than a
11 | reasonable redistribution fee) this data and its documentation for
12 | any purpose is hereby granted, provided that the above copyright notice
13 | appear in all copies, that both that copyright notice and this
14 | permission notice appear in supporting documentation, and that the name
15 | of GSHHG not be used in advertising or publicity pertaining to
16 | distribution of the software without specific, written prior permission.
17 | The GSHHG package may be included in a bundled distribution of software
18 | for which a fee may be charged. The University of Hawaii (UH) and the
19 | National Oceanic and Atmospheric Administration (NOAA) make no
20 | representations about the suitability of this software for any purpose.
21 | It is provided "as is" without expressed or implied warranty. It is
22 | provided with no support and without obligation on the part of UH or
23 | NOAA, to assist in its use, correction, modification, or enhancement.
24 |
--------------------------------------------------------------------------------
/Map/Resources/Maps/README.md:
--------------------------------------------------------------------------------
1 | ## 描画範囲
2 |
3 | - 日本地図は、左上北緯47度・東経121度、右下北緯23度・東経150度です。
4 |
5 | ## ライセンス
6 |
7 | - ファイル名に `gsi` を含む地図データの日本部分は、 [地理院タイル](https://maps.gsi.go.jp/development/ichiran.html) を使用しています。 [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/legalcode.ja) 互換です。
8 | - それ以外の地図データは、 [GSHHG](https://www.soest.hawaii.edu/pwessel/gshhg/) のデータを使用して [GMT](https://www.generic-mapping-tools.org/) で生成したものです。 それぞれ LGPL v3 です。
9 |
10 |
--------------------------------------------------------------------------------
/Map/Resources/Maps/japan-gsi_1024-8bit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Maps/japan-gsi_1024-8bit.png
--------------------------------------------------------------------------------
/Map/Resources/Maps/japan-gsi_2048-8bit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Maps/japan-gsi_2048-8bit.png
--------------------------------------------------------------------------------
/Map/Resources/Maps/japan-gsi_4096-8bit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Maps/japan-gsi_4096-8bit.png
--------------------------------------------------------------------------------
/Map/Resources/Maps/japan-gsi_8192-8bit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Maps/japan-gsi_8192-8bit.png
--------------------------------------------------------------------------------
/Map/Resources/Maps/japan-large-gsimaps.xcfbz2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Maps/japan-large-gsimaps.xcfbz2
--------------------------------------------------------------------------------
/Map/Resources/Maps/japan-small-gsimaps.xcfbz2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Maps/japan-small-gsimaps.xcfbz2
--------------------------------------------------------------------------------
/Map/Resources/Maps/japan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Maps/japan.png
--------------------------------------------------------------------------------
/Map/Resources/Maps/japan_gmt_3200dpi.xcfbz2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Maps/japan_gmt_3200dpi.xcfbz2
--------------------------------------------------------------------------------
/Map/Resources/Maps/world_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Maps/world_1024.png
--------------------------------------------------------------------------------
/Map/Resources/Maps/world_242.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Maps/world_242.png
--------------------------------------------------------------------------------
/Map/Resources/Maps/world_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Maps/world_512.png
--------------------------------------------------------------------------------
/Map/Resources/Maps/world_640.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/Map/Resources/Maps/world_640.png
--------------------------------------------------------------------------------
/Map/Resources/Points/EEWPrefs2EarthquakeAreaCodes.csv:
--------------------------------------------------------------------------------
1 | EEW府県予報区地域コード,区域コード1...
2 | 160,100,101,102,115,116,117,120,121,122
3 | 161,105,106,107,110,119,145,146,150,151,152
4 | 162,125,126,127,130,131,135,136,139
5 | 163,140,141,142,155,156,157,160,161,165,166,167
6 | 164,200,201,202,203
7 | 165,210,211,212,213
8 | 166,220,222,221
9 | 167,230,231,232,233
10 | 168,240,241,242,243
11 | 169,250,251,252
12 | 170,300,301
13 | 171,310,311
14 | 172,320,321
15 | 173,330,331,332
16 | 174,340,341,342
17 | 175,350,351,352
18 | 176,355,356,354,357,358
19 | 177,359
20 | 178,360,361
21 | 179,370,371,372,375
22 | 180,380,381
23 | 181,390,391
24 | 182,400,401
25 | 183,412,411
26 | 184,420,421,422
27 | 185,430,431,432
28 | 186,440,441,442,443
29 | 187,450,451
30 | 188,460,461,462
31 | 189,500,501
32 | 190,510,511
33 | 191,520,521
34 | 192,530,531,532,535
35 | 193,540
36 | 194,550,551
37 | 195,560,562,563
38 | 196,570,571,575
39 | 197,580,581
40 | 198,590,591,592
41 | 199,600,601
42 | 360,610,611
43 | 361,620,621,622
44 | 362,630,631,632
45 | 363,700,703,704,702
46 | 364,710,711,712,713
47 | 365,720,721
48 | 366,730,731,732,735,736,737
49 | 367,740,741,742,743
50 | 368,750,751,752,753
51 | 369,760,761,762,763
52 | 370,770,771,774,775,776,777
53 | 371,778,779
54 | 372,800,801,802
55 | 373,803
56 | 374,804
57 | 375,805,806,807
--------------------------------------------------------------------------------
/Map/Resources/Points/README.md:
--------------------------------------------------------------------------------
1 | ## ライセンス
2 |
3 | - earthquake.json, earthquake_?.json, tsunami.json: 気象庁が公開している情報です (CC BY 4.0)
4 | - userquake.json: 気象庁が公開している情報 (CC BY 4.0) を加工したものです
5 | - Areas.csv: 区域名は [気象庁 \| 緊急地震速報や震度情報で用いる区域の名称](https://www.data.jma.go.jp/svd/eqev/data/joho/shindo-name.html) に基づきます (CC BY 4.0)
6 | - Stations.csv: [気象庁 \| 震度観測点](https://www.data.jma.go.jp/svd/eqev/data/intens-st/index.html) に基づきます (CC BY 4.0)
7 |
8 | 記載がないものは、ルートディレクトリの LICENSE に従います。
9 |
--------------------------------------------------------------------------------
/Map/Resources/Points/TsunamiAreaCodes.csv:
--------------------------------------------------------------------------------
1 | 100,北海道太平洋沿岸東部
2 | 101,北海道太平洋沿岸中部
3 | 102,北海道太平洋沿岸西部
4 | 110,北海道日本海沿岸北部
5 | 111,北海道日本海沿岸南部
6 | 120,オホーツク海沿岸
7 | 200,青森県日本海沿岸
8 | 201,青森県太平洋沿岸
9 | 202,陸奥湾
10 | 210,岩手県
11 | 220,宮城県
12 | 230,秋田県
13 | 240,山形県
14 | 250,福島県
15 | 300,茨城県
16 | 310,千葉県九十九里・外房
17 | 311,千葉県内房
18 | 312,東京湾内湾
19 | 320,伊豆諸島
20 | 321,小笠原諸島
21 | 330,相模湾・三浦半島
22 | 340,新潟県上中下越
23 | 341,佐渡
24 | 350,富山県
25 | 360,石川県能登
26 | 361,石川県加賀
27 | 370,福井県
28 | 380,静岡県
29 | 390,愛知県外海
30 | 391,伊勢・三河湾
31 | 400,三重県南部
32 | 500,京都府
33 | 510,大阪府
34 | 520,兵庫県北部
35 | 521,兵庫県瀬戸内海沿岸
36 | 522,淡路島南部
37 | 530,和歌山県
38 | 540,鳥取県
39 | 550,島根県出雲・石見
40 | 551,隠岐
41 | 560,岡山県
42 | 570,広島県
43 | 580,徳島県
44 | 590,香川県
45 | 600,愛媛県宇和海沿岸
46 | 601,愛媛県瀬戸内海沿岸
47 | 610,高知県
48 | 700,山口県日本海沿岸
49 | 701,山口県瀬戸内海沿岸
50 | 710,福岡県瀬戸内海沿岸
51 | 711,福岡県日本海沿岸
52 | 712,有明・八代海
53 | 720,佐賀県北部
54 | 730,長崎県西方
55 | 731,壱岐・対馬
56 | 740,熊本県天草灘沿岸
57 | 750,大分県瀬戸内海沿岸
58 | 751,大分県豊後水道沿岸
59 | 760,宮崎県
60 | 770,鹿児島県東部
61 | 771,種子島・屋久島地方
62 | 772,奄美群島・トカラ列島
63 | 773,鹿児島県西部
64 | 800,沖縄本島地方
65 | 801,大東島地方
66 | 802,宮古島・八重山地方
67 |
--------------------------------------------------------------------------------
/Map/Resources/Points/UserquakeAreas2EarthquakeAreaCodes.csv:
--------------------------------------------------------------------------------
1 | 地域コード,区域コード1,区域コード2,区域コード3
2 | 010,100,101,102
3 | 015,105,106,107
4 | 020,110,119
5 | 025,115,116,117
6 | 030,120,121,122
7 | 035,125,126,127
8 | 040,130,131
9 | 045,135,136,139
10 | 050,140,141,142
11 | 055,145,146
12 | 065,155,156,157
13 | 060,150,151,152
14 | 070,160,161
15 | 075,165,166,167
16 | 100,200,201
17 | 105,202
18 | 106,203
19 | 110,210
20 | 111,211
21 | 115,212,213
22 | 120,220,12201,12202
23 | 125,221,12211,12212
24 | 130,230,231
25 | 135,232,233
26 | 140,240
27 | 141,241
28 | 142,242
29 | 143,243
30 | 150,250
31 | 151,251
32 | 152,252
33 | 200,300
34 | 205,301
35 | 210,310
36 | 215,311
37 | 220,320
38 | 225,321
39 | 230,330
40 | 231,331
41 | 232,332
42 | 240,340
43 | 241,341
44 | 242,342
45 | 250,350,351,352
46 | 255,355,356,354
47 | 260,357,358
48 | 265,359
49 | 270,360
50 | 275,361
51 | 300,370
52 | 301,371
53 | 302,372
54 | 305,375
55 | 310,380
56 | 315,381
57 | 320,390
58 | 325,391
59 | 330,400
60 | 335,401
61 | 340,412
62 | 345,411
63 | 350,420
64 | 351,421
65 | 355,422
66 | 400,430
67 | 405,431,432
68 | 410,440
69 | 411,441
70 | 415,442
71 | 416,443
72 | 420,450
73 | 425,451
74 | 430,460,461
75 | 435,462
76 | 440,500
77 | 445,501
78 | 450,510
79 | 455,511
80 | 460,520
81 | 465,521
82 | 470,530
83 | 475,531,532,535
84 | 480,540
85 | 490,550
86 | 495,551
87 | 500,560
88 | 505,562,563
89 | 510,570
90 | 515,571
91 | 514,575
92 | 520,580
93 | 525,581
94 | 530,590
95 | 535,591,592
96 | 540,700
97 | 545,703,704
98 | 541,702
99 | 550,600
100 | 555,601
101 | 560,610,611
102 | 570,620
103 | 575,621
104 | 576,622
105 | 580,630
106 | 581,631
107 | 582,632
108 | 600,710
109 | 601,711
110 | 602,712
111 | 605,713
112 | 610,720
113 | 615,721
114 | 620,730
115 | 625,731,732
116 | 630,735,736
117 | 635,737
118 | 640,740
119 | 641,741
120 | 645,742
121 | 646,743
122 | 650,750
123 | 651,751
124 | 655,753
125 | 656,752
126 | 660,760
127 | 661,761
128 | 665,762
129 | 666,763
130 | 670,770,775
131 | 675,771
132 | 680,776,777
133 | 685,778,779,774
134 | 700,800
135 | 701,801
136 | 702,802
137 | 705,805,806,807
138 | 706,804
139 | 710,803
--------------------------------------------------------------------------------
/MapTest/EarthquakeDrawTest.cs:
--------------------------------------------------------------------------------
1 | using Map.Controller;
2 | using Map.Model;
3 |
4 | using NUnit.Framework;
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.IO;
9 | using System.Linq;
10 | using System.Security.Cryptography;
11 | using System.Threading;
12 |
13 | namespace MapTest
14 | {
15 | public class EarthquakeDrawTest
16 | {
17 | static readonly Func[] drawActions = {
18 | // 2022/04/07 22:26
19 | () => new MapDrawer
20 | {
21 | Trim = true,
22 | MapType = MapType.JAPAN_1024,
23 | Hypocenter = new GeoCoordinate(29.4, 129.5),
24 | ObservationPoints = new List
25 | {
26 | new("鹿児島県", "鹿児島十島村", 10),
27 | },
28 | }.DrawAsPng(),
29 | // 2022/04/07 09:30
30 | () => new MapDrawer
31 | {
32 | Trim = true,
33 | MapType = MapType.JAPAN_2048,
34 | Hypocenter = new GeoCoordinate(34.9, 137.5),
35 | }.DrawAsPng(),
36 |
37 | // 2022/04/08 22:05
38 | () => new MapDrawer
39 | {
40 | MapType = MapType.JAPAN_8192,
41 | ObservationPoints = new List
42 | {
43 | new("", "石川県能登", 40),
44 | },
45 | }.DrawAsPng(),
46 | };
47 |
48 | [TestCaseSource(nameof(drawActions))]
49 | public void InternationalizationTest(Func drawAction)
50 | {
51 | var drawResults = Internationalization.CultureNames.Select(cultureName =>
52 | {
53 | Internationalization.ReinstantiateSingletonInstances(cultureName);
54 | var ms = new MemoryStream();
55 | drawAction().CopyTo(ms);
56 | return ms.ToArray();
57 | }).ToList();
58 |
59 | drawResults.ForEach(drawResult =>
60 | {
61 | Assert.AreEqual(drawResults[0].Length, drawResult.Length);
62 | Assert.AreEqual(drawResults[0], drawResult);
63 | });
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/MapTest/Internationalization.cs:
--------------------------------------------------------------------------------
1 | using Map.Model;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace MapTest
11 | {
12 | internal static class Internationalization
13 | {
14 | public static string[] CultureNames { get; } =
15 | {
16 | "ja-JP",
17 | "en-US",
18 | "en-GB",
19 | "fr-FR",
20 | };
21 |
22 | public static void ReinstantiateSingletonInstances(string cultureName)
23 | {
24 | Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
25 |
26 | var targets = new Dictionary
27 | {
28 | { typeof(ObservationAreas), "Instance" },
29 | { typeof(Stations), "Instance" },
30 | { typeof(TsunamiAreas), "Instance" },
31 | { typeof(UserquakeAreas), "Instance" },
32 | };
33 |
34 | foreach (var target in targets)
35 | {
36 | var targetType = target.Key;
37 | var targetProperty = target.Value;
38 |
39 | var instance = Activator.CreateInstance(targetType, true);
40 | var property = targetType.GetProperty(targetProperty);
41 | property?.SetValue(null, instance);
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/MapTest/MapTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 |
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | PreserveNewest
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | all
26 | runtime; build; native; contentfiles; analyzers; buildtransitive
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/MapTest/StationsShorteningTest.cs:
--------------------------------------------------------------------------------
1 | using Map.Model;
2 |
3 | using NUnit.Framework;
4 |
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 |
9 | namespace MapTest
10 | {
11 | public class StationsShorteningTest
12 | {
13 | [TestCase]
14 | public void ShorteningTest()
15 | {
16 | var stations = Stations.Instance;
17 | var prop = stations.GetType().GetField("stations", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
18 | var stationMap = (Dictionary)(prop.GetValue(stations));
19 |
20 | var actual = stationMap.Values.Distinct().Select((station) =>
21 | {
22 | if (station.IsArea) { return new string[] { station.Name, station.Name }; }
23 |
24 | var match = StationNameShorter.ShortenPattern.Match(station.Name);
25 | if (match.Success)
26 | {
27 | return new string[] { station.Name, match.Groups[1].Value };
28 | }
29 | return new string[] { station.Name, station.Name };
30 | }).Select((array) => string.Join(',', array));
31 |
32 | var directory = System.AppDomain.CurrentDomain.BaseDirectory;
33 | var filename = Path.Combine(directory, @"TestData/ShorteningTest.csv");
34 |
35 | // Note. expect を更新する場合
36 | // File.WriteAllLines(filename, actual, System.Text.Encoding.UTF8);
37 |
38 | var expect = File.ReadAllLines(filename, System.Text.Encoding.UTF8);
39 | CollectionAssert.AreEquivalent(expect, actual);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/MapTest/TsunamiDrawTest.cs:
--------------------------------------------------------------------------------
1 | using Map.Controller;
2 | using Map.Model;
3 |
4 | using NUnit.Framework;
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Threading;
9 |
10 | namespace MapTest
11 | {
12 | public class TsunamiDrawTest
13 | {
14 | [TestCaseSource(typeof(Internationalization), nameof(Internationalization.CultureNames))]
15 | public void InternationalizationTest(string cultureName)
16 | {
17 | Internationalization.ReinstantiateSingletonInstances(cultureName);
18 |
19 | // 2022/03/16 23:39
20 | new MapDrawer
21 | {
22 | MapType = MapType.JAPAN_2048,
23 | TsunamiPoints = new List
24 | {
25 | new TsunamiPoint("宮城県", TsunamiCategory.Advisory),
26 | new TsunamiPoint("福島県", TsunamiCategory.Advisory),
27 | },
28 | }.DrawAsPng();
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/MapTest/UserquakeDrawTest.cs:
--------------------------------------------------------------------------------
1 | using Map.Controller;
2 | using Map.Model;
3 |
4 | using NUnit.Framework;
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Threading;
9 |
10 | namespace MapTest
11 | {
12 | public class UserquakeDrawTest
13 | {
14 | [TestCaseSource(typeof(Internationalization), nameof(Internationalization.CultureNames))]
15 | public void InternationalizationTest(string cultureName)
16 | {
17 | Internationalization.ReinstantiateSingletonInstances(cultureName);
18 |
19 | new MapDrawer
20 | {
21 | MapType = MapType.JAPAN_2048,
22 | UserquakePoints = new List
23 | {
24 | new UserquakePoint("010", 0.5),
25 | new UserquakePoint("700", 0.5),
26 | },
27 | }.DrawAsPng();
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/PKCSPeerCrypto/PKCSPeerCrypto.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 |
6 |
7 |
8 | embedded
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/PKCSPeerCrypto/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "PKCSPeerCrypto": {
4 | "commandName": "Project",
5 | "nativeDebugging": false
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/PKCSPeerCryptoTest/PKCSPeerCryptoTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/PKCSPeerCryptoTest/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "PKCSPeerCryptoTest": {
4 | "commandName": "Project",
5 | "nativeDebugging": false
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/PKCSPeerCryptoTest/SampleTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using NUnit.Framework;
7 |
8 | namespace PKCSPeerCryptoTest
9 | {
10 | [TestFixture]
11 | public class SampleTest
12 | {
13 | [TestCase]
14 | public void SampleTest_001()
15 | {
16 | Assert.Pass("PKCSPeerCryptoTest: NUnit works!");
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Updater/UpdateEntry.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Updater
8 | {
9 | public class UpdateEntry
10 | {
11 | public string path { get; set; }
12 | public string version { get; set; }
13 | public string sha256Digest { get; set; }
14 | public bool required { get; set; }
15 | public bool allowDigestMismatch { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Updater/Updater.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/WpfClient/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/WpfClient/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace WpfClient
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | protected override void OnStartup(StartupEventArgs e)
17 | {
18 | base.OnStartup(e);
19 |
20 | MainWindow = new MainWindow();
21 | MainWindow.Show();
22 | if (ConfigurationManager.Configuration.MinimizeAtBoot)
23 | {
24 | MainWindow.Hide();
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/WpfClient/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/WpfClient/EPSPDataView/DetailItemView.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 |
8 | namespace WpfClient.EPSPDataView
9 | {
10 | public enum TextStyles
11 | {
12 | Title,
13 | Name,
14 | // 地震情報
15 | Prefecture,
16 | Scale,
17 | Eruption, // 噴火
18 | FreeFormComment, // 自由付加文
19 | // 津波予報
20 | Section,
21 | MajorWarning,
22 | Warning,
23 | Advisory,
24 | }
25 |
26 | public class DetailItemView
27 | {
28 | public string Text { get; init; }
29 | public TextStyles TextStyle { get; init; }
30 | public string ScaleIconPath { get; init; }
31 |
32 | public DetailItemView(string text, TextStyles style, int scale = -1)
33 | {
34 | this.Text = text;
35 | this.TextStyle = style;
36 | this.ScaleIconPath = $"/Resources/Scales/scale_{scale}.png";
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/WpfClient/EPSPDataView/EPSPEEWTestView.cs:
--------------------------------------------------------------------------------
1 | using Client.Peer;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace WpfClient.EPSPDataView
10 | {
11 | public class EPSPEEWTestView
12 | {
13 | public EPSPEEWTestEventArgs EventArgs { get; init; }
14 |
15 | public string Time => EventArgs.ReceivedAt.ToString("dd日HH時mm分");
16 |
17 | public string DetailTitle => $"緊急地震速報 発表検出({(EventArgs is not null ? EventArgs.ReceivedAt.ToString("dd日HH時mm分ss秒") : "")})";
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/WpfClient/EPSPDataView/Factory.cs:
--------------------------------------------------------------------------------
1 | using Client.App.Userquake;
2 | using Client.Peer;
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace WpfClient.EPSPDataView
11 | {
12 | public static class Factory
13 | {
14 | public static object WrapEventArgs(EventArgs eventArgs, Func protocolTime, IFrameModel frameModel)
15 | {
16 | if (eventArgs is EPSPQuakeEventArgs quake)
17 | {
18 | return new EPSPQuakeView() { EventArgs = quake, FrameModel = frameModel, IsExpanded = quake.InformationType == QuakeInformationType.Foreign && quake.FreeCommentList?.Count > 0 };
19 | }
20 |
21 | if (eventArgs is EPSPTsunamiEventArgs tsunami)
22 | {
23 | return new EPSPTsunamiView() { EventArgs = tsunami, FrameModel = frameModel };
24 | }
25 |
26 | if (eventArgs is EPSPEEWTestEventArgs eewTest)
27 | {
28 | return new EPSPEEWTestView() { EventArgs = eewTest };
29 | }
30 |
31 | if (eventArgs is EPSPEEWEventArgs eew)
32 | {
33 | return new EPSPEEWView(eew, frameModel);
34 | }
35 |
36 | if (eventArgs is UserquakeEvaluateEventArgs userquake)
37 | {
38 | return new EPSPUserquakeView(userquake, protocolTime, frameModel);
39 | }
40 |
41 | return null;
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/WpfClient/LicenseViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Collections.ObjectModel;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace WpfClient
11 | {
12 | public class LicenseViewModel
13 | {
14 | public ObservableCollection Licenses { get; init; }
15 |
16 | public LicenseViewModel()
17 | {
18 | var licenseItems = License.ResourceManager.GetResourceSet(Thread.CurrentThread.CurrentCulture, true, true).OfType().Where(e => e.Value is string).OrderBy(e => e.Key).Select(e => new LicenseModel() { Name = (string)e.Key, Text = (string)e.Value });
19 | Licenses = new ObservableCollection(licenseItems);
20 | }
21 | }
22 |
23 | public class LicenseModel
24 | {
25 | public string Name { get; init; }
26 | public string Text { get; init; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/WpfClient/LicenseWindow.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/WpfClient/LicenseWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Shapes;
14 |
15 | namespace WpfClient
16 | {
17 | ///
18 | /// LicenseWindow.xaml の相互作用ロジック
19 | ///
20 | public partial class LicenseWindow : Window
21 | {
22 | public LicenseWindow()
23 | {
24 | InitializeComponent();
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/WpfClient/Pages/Information.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using System.Windows.Input;
4 | using System.Windows.Navigation;
5 |
6 | namespace WpfClient.Pages
7 | {
8 | ///
9 | /// Information.xaml の相互作用ロジック
10 | ///
11 | public partial class Information : Page
12 | {
13 | public Information()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
19 | {
20 | var viewModel = (InformationViewModel)DataContext;
21 | viewModel.SelectItem = ((ModernWpf.Controls.ListView)sender).SelectedItem;
22 | }
23 |
24 | private void Frame_Navigated(object sender, NavigationEventArgs e)
25 | {
26 | ((FrameworkElement)e.Content).DataContext = ((InformationViewModel)DataContext).SelectItem;
27 | }
28 |
29 | private void Frame_SizeChanged(object sender, SizeChangedEventArgs e)
30 | {
31 | var viewModel = (InformationViewModel)DataContext;
32 | viewModel.FrameWidth = e.NewSize.Width;
33 | viewModel.FrameHeight = e.NewSize.Height;
34 | }
35 |
36 | private void TutorialPanel_MouseDown(object sender, MouseButtonEventArgs e)
37 | {
38 | var viewModel = (InformationViewModel)DataContext;
39 | viewModel.TutorialVisibility = Visibility.Hidden;
40 | }
41 |
42 | private void Frame_Navigating(object sender, NavigatingCancelEventArgs e)
43 | {
44 | if (e.NavigationMode != NavigationMode.New) { e.Cancel = true; }
45 | }
46 |
47 | //private void RefreshButton_Click(object sender, RoutedEventArgs e)
48 | //{
49 | // Program.RefreshInformation();
50 | //}
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/WpfClient/Pages/InformationTemplateSelector.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 |
4 | using WpfClient.EPSPDataView;
5 |
6 | namespace WpfClient.Pages
7 | {
8 | public class InformationTemplateSelector : DataTemplateSelector
9 | {
10 | public override DataTemplate SelectTemplate(object item, DependencyObject container)
11 | {
12 | var element = container as FrameworkElement;
13 |
14 | if (item is EPSPQuakeView)
15 | {
16 | return element.FindResource("EarthquakeItem") as DataTemplate;
17 | }
18 |
19 | if (item is EPSPTsunamiView)
20 | {
21 | return element.FindResource("TsunamiItem") as DataTemplate;
22 | }
23 |
24 | if (item is EPSPEEWTestView)
25 | {
26 | return element.FindResource("EEWTestItem") as DataTemplate;
27 | }
28 |
29 | if (item is EPSPEEWView eew)
30 | {
31 | if (eew.EventArgs.IsCancelled)
32 | {
33 | return element.FindResource("EEWCancelledItem") as DataTemplate;
34 | }
35 | return element.FindResource("EEWItem") as DataTemplate;
36 | }
37 |
38 | if (item is EPSPUserquakeView)
39 | {
40 | return element.FindResource("UserquakeItem") as DataTemplate;
41 | }
42 |
43 | return null;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/WpfClient/Pages/Informations/DetailDescriptionTemplateSelector.cs:
--------------------------------------------------------------------------------
1 | using Client.App.Userquake;
2 | using Client.Peer;
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Windows;
10 | using System.Windows.Controls;
11 |
12 | using WpfClient.EPSPDataView;
13 |
14 | namespace WpfClient.Pages.Informations
15 | {
16 | public class DetailDescriptionTemplateSelector : DataTemplateSelector
17 | {
18 | public override DataTemplate SelectTemplate(object item, DependencyObject container)
19 | {
20 | var element = container as FrameworkElement;
21 |
22 | if (item is not DetailItemView itemView)
23 | {
24 | return null;
25 | }
26 |
27 | return itemView.TextStyle switch
28 | {
29 | TextStyles.Title => element.FindResource("DetailHeaderItem") as DataTemplate,
30 | TextStyles.Name => element.FindResource("DetailNameItem") as DataTemplate,
31 | // 地震情報向け
32 | TextStyles.Prefecture => element.FindResource("DetailPrefectureItem") as DataTemplate,
33 | TextStyles.Scale => element.FindResource("DetailScaleItem") as DataTemplate,
34 | TextStyles.Eruption => element.FindResource("DetailEruptionItem") as DataTemplate,
35 | TextStyles.FreeFormComment => element.FindResource("DetailFreeFormCommentItem") as DataTemplate,
36 | // 津波予報向け
37 | TextStyles.Section => element.FindResource("DetailSectionItem") as DataTemplate,
38 | TextStyles.MajorWarning => element.FindResource("DetailMajorWarningItem") as DataTemplate,
39 | TextStyles.Warning => element.FindResource("DetailWarningItem") as DataTemplate,
40 | TextStyles.Advisory => element.FindResource("DetailAdvisoryItem") as DataTemplate,
41 | _ => throw new NotImplementedException(),
42 | };
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/WpfClient/Pages/Informations/EEW.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace WpfClient.Pages.Informations
17 | {
18 | ///
19 | /// EEW.xaml の相互作用ロジック
20 | ///
21 | public partial class EEW : Page
22 | {
23 | public EEW()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/WpfClient/Pages/Informations/EEWCancelled.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace WpfClient.Pages.Informations
4 | {
5 | ///
6 | /// EEWCancelled.xaml の相互作用ロジック
7 | ///
8 | public partial class EEWCancelled : Page
9 | {
10 | public EEWCancelled()
11 | {
12 | InitializeComponent();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/WpfClient/Pages/Informations/Earthquake.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace WpfClient.Pages.Informations
17 | {
18 | ///
19 | /// Earthquake.xaml の相互作用ロジック
20 | ///
21 | public partial class Earthquake : Page
22 | {
23 | public Earthquake()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/WpfClient/Pages/Informations/Tsunami.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 | using System.Windows.Threading;
16 |
17 | using WpfClient.EPSPDataView;
18 |
19 | namespace WpfClient.Pages.Informations
20 | {
21 | ///
22 | /// Tsunami.xaml の相互作用ロジック
23 | ///
24 | public partial class Tsunami : Page
25 | {
26 | public Tsunami()
27 | {
28 | InitializeComponent();
29 | this.DataContextChanged += Tsunami_DataContextChanged;
30 | }
31 |
32 | private void Tsunami_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
33 | {
34 | if (this.DataContext is null) { return; }
35 | var view = (EPSPTsunamiView)this.DataContext;
36 | if (view.EventArgs is null) { return; }
37 |
38 | var count = 0;
39 | var timer = new DispatcherTimer(DispatcherPriority.Normal)
40 | {
41 | Interval = TimeSpan.FromSeconds(0.5),
42 | };
43 | timer.Tick += (s, e) =>
44 | {
45 | count = (count + 1) % 6;
46 | if (count == 0)
47 | {
48 | FrontImage.Visibility = Visibility.Hidden;
49 | }
50 | if (count == 1)
51 | {
52 | FrontImage.Visibility = Visibility.Visible;
53 | }
54 | };
55 |
56 | timer.Start();
57 | DataContextChanged += (s, e) => timer.Stop();
58 | Unloaded += (s, e) => timer.Stop();
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/WpfClient/Pages/Informations/TsunamiCategoryText.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace WpfClient.Pages.Informations
17 | {
18 | ///
19 | /// TsunamiCategoryText.xaml の相互作用ロジック
20 | ///
21 | public partial class TsunamiCategoryText : Grid
22 | {
23 | public string Text { get; set; } = "";
24 | public string BackgroundColor { get; set; } = "White";
25 |
26 | public TsunamiCategoryText()
27 | {
28 | InitializeComponent();
29 | DataContext = this;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/WpfClient/Pages/Informations/Unknown.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/WpfClient/Pages/Informations/Unknown.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace WpfClient.Pages.Informations
17 | {
18 | ///
19 | /// Unknown.xaml の相互作用ロジック
20 | ///
21 | public partial class Unknown : Page
22 | {
23 | public Unknown()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/WpfClient/Pages/Informations/Userquake.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace WpfClient.Pages.Informations
17 | {
18 | ///
19 | /// Userquake.xaml の相互作用ロジック
20 | ///
21 | public partial class Userquake : Page
22 | {
23 | public Userquake()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/WpfClient/Pages/Status.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace WpfClient.Pages
17 | {
18 | ///
19 | /// Status.xaml の相互作用ロジック
20 | ///
21 | public partial class Status : Page
22 | {
23 | private LicenseWindow licenseWindow;
24 |
25 | public Status()
26 | {
27 | InitializeComponent();
28 | }
29 |
30 | private void ShowLicenseButton_Click(object sender, RoutedEventArgs e)
31 | {
32 | if (licenseWindow == null)
33 | {
34 | licenseWindow = new LicenseWindow();
35 | licenseWindow.Closed += (s, e) => { licenseWindow = null; };
36 | }
37 | licenseWindow.Show();
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/WpfClient/Properties/PublishProfiles/FolderProfile.pubxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 | Release
8 | Any CPU
9 | bin\Release\net6.0-windows10.0.18362.0\publish\
10 | FileSystem
11 | net6.0-windows10.0.18362.0
12 | false
13 | win-x64
14 | true
15 | false
16 |
17 |
--------------------------------------------------------------------------------
/WpfClient/Resources/Examples/japan_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Examples/japan_1024.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/eruption_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/eruption_black.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/eruption_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/eruption_white.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/p2pquake.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/p2pquake.ico
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/tsunami.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/tsunami_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/tsunami_black.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/tsunami_gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/tsunami_gray.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/tsunami_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/tsunami_red.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/tsunami_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/tsunami_white.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/tsunami_yellow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/tsunami_yellow.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/userquake_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/userquake_black.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/userquake_gray.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/userquake_gray.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/userquake_red.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/userquake_red.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/userquake_white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/userquake_white.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Icons/userquake_yellow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Icons/userquake_yellow.png
--------------------------------------------------------------------------------
/WpfClient/Resources/MapOverlays/description.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/MapOverlays/description.png
--------------------------------------------------------------------------------
/WpfClient/Resources/MapOverlays/loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/MapOverlays/loading.png
--------------------------------------------------------------------------------
/WpfClient/Resources/MapOverlays/loading.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/MapOverlays/loading.xcf
--------------------------------------------------------------------------------
/WpfClient/Resources/MapOverlays/quake_note.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/MapOverlays/quake_note.png
--------------------------------------------------------------------------------
/WpfClient/Resources/MapOverlays/tsunami_note_advisory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/MapOverlays/tsunami_note_advisory.png
--------------------------------------------------------------------------------
/WpfClient/Resources/MapOverlays/tsunami_note_majorwarning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/MapOverlays/tsunami_note_majorwarning.png
--------------------------------------------------------------------------------
/WpfClient/Resources/MapOverlays/tsunami_note_warning.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/MapOverlays/tsunami_note_warning.png
--------------------------------------------------------------------------------
/WpfClient/Resources/MapOverlays/userquake_note.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/MapOverlays/userquake_note.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Scales/scale_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Scales/scale_10.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Scales/scale_20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Scales/scale_20.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Scales/scale_30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Scales/scale_30.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Scales/scale_40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Scales/scale_40.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Scales/scale_45.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Scales/scale_45.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Scales/scale_46.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Scales/scale_46.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Scales/scale_50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Scales/scale_50.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Scales/scale_55.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Scales/scale_55.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Scales/scale_60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Scales/scale_60.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Scales/scale_70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Scales/scale_70.png
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/160.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/160.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/161.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/161.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/162.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/162.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/163.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/163.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/164.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/164.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/165.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/165.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/166.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/166.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/167.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/167.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/168.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/168.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/169.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/169.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/170.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/170.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/171.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/171.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/172.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/172.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/173.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/173.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/174.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/174.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/175.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/175.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/176.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/176.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/177.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/177.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/178.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/178.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/179.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/179.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/180.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/180.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/181.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/181.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/182.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/182.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/183.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/183.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/184.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/184.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/185.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/185.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/186.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/186.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/187.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/187.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/188.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/188.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/189.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/189.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/190.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/190.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/191.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/191.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/192.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/192.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/193.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/193.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/194.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/194.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/195.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/195.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/196.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/196.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/197.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/197.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/198.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/198.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/199.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/199.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/360.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/360.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/361.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/361.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/362.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/362.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/363.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/363.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/364.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/364.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/365.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/365.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/366.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/366.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/367.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/367.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/368.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/368.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/369.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/369.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/370.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/370.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/371.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/371.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/372.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/372.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/373.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/373.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/374.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/374.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/375.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/375.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/announce_areas.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/announce_areas.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/eew.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/eew.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/eew_cancelled.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/eew_cancelled.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/eew_followup.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/eew_followup.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW/guidance.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW/guidance.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/EEW_Beta.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/EEW_Beta.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/P2PQ_Snd0.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/P2PQ_Snd0.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/P2PQ_Snd1.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/P2PQ_Snd1.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/P2PQ_Snd2.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/P2PQ_Snd2.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/P2PQ_Snd3.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/P2PQ_Snd3.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/P2PQ_Snd4.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/P2PQ_Snd4.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/P2PQ_Snd9.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/P2PQ_Snd9.mp3
--------------------------------------------------------------------------------
/WpfClient/Resources/Sounds/P2PQ_Sndt.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/p2pquake/epsp-peer-cs/f1ac387c3ca2ca9f4d6273b312cbb750bc10876b/WpfClient/Resources/Sounds/P2PQ_Sndt.mp3
--------------------------------------------------------------------------------
/WpfClient/Utils/ScaleConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace WpfClient.Utils
8 | {
9 | public static class ScaleConverter
10 | {
11 | public static int Str2Int(string scale)
12 | {
13 | return scale switch
14 | {
15 | "1" => 10,
16 | "2" => 20,
17 | "3" => 30,
18 | "4" => 40,
19 | "5弱" => 45,
20 | "5弱以上(推定)" => 46,
21 | "5強" => 50,
22 | "6弱" => 55,
23 | "6強" => 60,
24 | "7" => 70,
25 | _ => -1,
26 | };
27 | }
28 |
29 | public static string Int2Str(int scale)
30 | {
31 | return scale switch
32 | {
33 | 10 => "1",
34 | 20 => "2",
35 | 30 => "3",
36 | 40 => "4",
37 | 45 => "5弱",
38 | 46 => "5弱以上(推定)",
39 | 50 => "5強",
40 | 55 => "6弱",
41 | 60 => "6強",
42 | 70 => "7",
43 | _ => "不明",
44 | };
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/WpfClient/Utils/TsunamiCategoryConverter.cs:
--------------------------------------------------------------------------------
1 | using Client.Peer;
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace WpfClient.Utils
10 | {
11 | public static class TsunamiCategoryConverter
12 | {
13 | public static string String(TsunamiCategory category) => category switch
14 | {
15 | TsunamiCategory.MajorWarning => "大津波警報",
16 | TsunamiCategory.Warning => "津波警報",
17 | TsunamiCategory.Advisory => "津波注意報",
18 | _ => "津波予報"
19 | };
20 | }
21 | }
22 |
--------------------------------------------------------------------------------