[ カテゴリー » PC関連 ]

ieServerにcurlでアクセスするとエラーになる

無料のDDNSサービスieServerの更新作業をcurlで自動化している人もそれなりにいると思います。

先日Raspberry Pi 4を入手したのでRaspberry Pi OS busterを入れて、ieServerに対してcurlコマンドを使用したところ、

curl: (35) error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure

とエラー。どうやらサーバー側のSSLが脆弱性のある古いものの場合、最近のクライアントは接続拒否するLink らしい。SSLライブラリで拒否しているみたいなのでwgetでもエラー。

サーバー側が対応してくれるのが一番いいのですが、とりあえずクライアントで対処してみます。古いcurlにダウングレードするのも手ですが、問題があるから接続拒否するようになったわけで、他サーバーへのアクセスまで巻き込みたくない。というわけで古いcurlを入れたDockerコンテナを作り、ieServerだけこいつでアクセスすることにします。

まずDockerfile。Alpineを使いたいところですがARMがサポートされだした3.6でもcurlがエラーを出したのでDebian Jessieにしてます。x86ならAlpineでも行けるかと。
FROM debian:8.11-slim
RUN apt-get update && apt-get install -y curl
CMD curl -X POST -F "username=$USERNAME" -F "password=$PASSWORD" -F "domain=$DOMAIN" -F 'updatehost=1' https://ieserver.net/cgi-bin/dip.cgiLink 
ビルド&ラン。sudo省略 & 全角は各自の環境に置き換えてください。
docker build -t イメージタグ .
docker run -e USERNAME=ユーザー名 -e PASSWORD=パスワード -e DOMAIN=ドメイン --name コンテナ名 イメージタグ
ieServerのIP更新ページLink にアクセスして、アドレス更新時刻がdocker runが終わった時くらいになっていれば成功。次回からはcronなどで
docker container start コンテナ名
で回せば良いかと。

[参考]

— posted by mu at 05:40 pm   commentComment [0]  pingTrackBack [0]

Windowsのネットワークドライブマップはユーザーごとに違うらしい

How can I access a mapped network drive with System.IO.DirectoryInfo? (stack overflow)Link

ネットワークドライブのマップはそれをしたユーザーのみに有効、ということらしい。知らなかった。コマンドラインからでも機能するからExplorer.exeで解釈しているショートカットとは違うけど、こいつもファイルシステムレベルの実装じゃないということか。

私もこのスレッドの下の方に書いてあるように、IISでホストされるWebアプリケーションがマップされたドライブを見つけられず頭を抱えていた状態。IISでホストされるプログラムは"IIS APPPOOL¥アプリケーションプール名"のユーザーで走るから、開発ユーザーでマップしたドライプは見えてなかったわけか。

今回はシンボリックリンクで回避しました。

— posted by mu at 08:03 pm   commentComment [0]  pingTrackBack [0]

WPF習作メモ2

こういうのを作りたいとします。Borderの中にあるチェックボックスをチェックすると、ボーダーの色と太さが変わるというもの。コードビハインド使えば何とでもなるので、XAMLのみ縛りで。
blog20191219-DataBindingToChild

こういうXAMLを書けば普通に動きます。今回の件でStackPanelは必要ないのですが、CheckBoxだけBorderで囲むなんて実用的じゃないですのでオマケ。

<Border>
    <Border.Style>
        <Style TargetType="{x:Type Border}">
            <Setter Property="BorderBrush" Value="Gray"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsChecked,ElementName=checkbox1}" Value="true">
                    <Setter Property="BorderBrush" Value="RoyalBlue"/>
                    <Setter Property="BorderThickness" Value="3"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>                
    </Border.Style>
    <StackPanel>
        <CheckBox Name="checkbox1" IsChecked="False" Content="Check for blue border"/>
        <TextBlock Text="Test"/>
    </StackPanel>
</Border>

ただこれの難点は内部のチェックボックスに固有の名前を与えているのでこういうのを作るたびにElementNameを変えたStyleを書く必要があり、メンテナンス性が悪いことです。Styleをリソースで定義して使いまわしたいわけです。子要素から親要素へのBindingはFindAncestorを使えばいいですが逆はどうするかというと、BorderのプロパティChildが内部のStackPanelを指しそれのプロパティChildren[0]がStackPanelの第1子要素CheckBoxを指してくれますので、Bindingパス Child.Children[0].IsCheckedで得られます。

ここからが本題。下記XAMLはうまく動きません。
<Window.Resources>
    <Style x:Key="BorderStyle1" TargetType="{x:Type Border}">
        <Setter Property="BorderBrush" Value="Gray"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Style.Triggers>
            <DataTrigger Binding="{Binding Child.Children[0].IsChecked}" Value="true">
                <Setter Property="BorderBrush" Value="RoyalBlue"/>
                <Setter Property="BorderThickness" Value="3"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Border Style="{StaticResource BorderStyle1}">
    <StackPanel>
        <CheckBox Name="checkbox1" IsChecked="False" Content="Check for blue border"/>
        <TextBlock Text="Test"/>
    </StackPanel>
</Border>

理由はXAMLは上から処理されていくから。BorderのStyle={StaticResource...}の部分でBindingパスを解決しようとするのですが、XAML内では後に書いてある子要素のStackPanelやCheckBoxはまだ処理されておらずオブジェクトとして存在してません。つまりBorderのChildはまだnullなのです。ElementNameの場合はXAML上で後ろの物でもちゃんと探してくれるのですが、こちらはダメのようです。

ならばStyleの設定をXAML上で後に書けばいいのです。というわけで、以下のXAMLは動きます。

<Window.Resources>
    <Style x:Key="BorderStyle1" TargetType="{x:Type Border}">
        <Setter Property="BorderBrush" Value="Gray"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Style.Triggers>
            <DataTrigger Binding="{Binding Child.Children[0].IsChecked,RelativeSource={RelativeSource Self}}" Value="true">
                <Setter Property="BorderBrush" Value="RoyalBlue"/>
                <Setter Property="BorderThickness" Value="3"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Border>
    <StackPanel>
        <CheckBox Name="checkbox1" IsChecked="False" Content="Check for blue border"/>
        <TextBlock Text="Test"/>
    </StackPanel>
    <Border.Style>
        <Style TargetType="{x:Type Border}" BasedOn="{StaticResource BorderStyle1}"/>
    </Border.Style>
</Border>
注意すべき点があります。
  • Border.Style内のStyleにTargetTypeをちゃんと指定すること。そうでないとこのStyleはUIElementの物として扱われ、その継承クラスであるBorder用に作られたBorderStyle1をBasedOnとして設定できません。
  • リソースStyleでのBindingにRelativeSource Self設定が無いと動きません。これの理由は不明。

— posted by mu at 01:21 am   commentComment [0]  pingTrackBack [0]

WPF習作メモ

blog20191215-WPFTest1

地図などを背景にして、印を上に書き加えることを想定してます。データはグループ(Group)配列とそれぞれに位置データ(Spot)配列の階層構造になってます。例えばグループとして、レストラン・コンビニなどの業種、Spotとしては店の位置とその規模を円の大きさで示すなど。あとエスコンのレーダーかいくぐりミッションとか

コードは以下のことができます。

  • 左のリスト
    • データグループ名(0~4)を表示
    • 行を選択すると対応するグループに属する円を黄色にする
  • 右のチャート
    • 各Spotデータが示す位置に円を描画、円の中央にはグループ名
    • 円の上にカーソルを置くと同じグループに属する円が太くなる
    • 円をクリックするとそのグループが選択状態になり黄色に、また左のリストの選択もそれに対応する

左はいたって普通のListBoxですが、右もListBoxです。ListBoxをカスタマイズするにしても通常ItemsPanelにはStackPanelやWrapPanelを指定するでしょうが、ここではCanvasを使うことで自由な位置への配置を可能にします。その代わり位置を指定しないと全部左上に重なってしまうので、ItemContainerStyleでCanvas.LeftとCanvas.Top添付プロパティを設定します。

同一グループ内の複数の円を描くにはItemsControlを使用。ItemsControlはListBoxの親クラスです。ListBoxを使用すると同一グループ内の個々の円に対する選択が発生してしまうのでこちらを使用してますが、用途によってはListBoxでも可。つまりListBoxの中にListBoxを使っていることになります。下の図でいえば、左のListBoxで選択状態にある"0"に相当するのが、右の黄色箱で囲んだ部分になります。左右とも同じデータをバインディングしたListBox、描画方法が違うだけ。

左右で選択が連携するのは簡単、左のSelectedItemを右のSelectedItemにTwoWayでバインドするだけ。下図の黄色箱どこでもクリックすれば左のListBoxの0の行をクリックしたのと同じはずですが、黄色箱のItemsPanelとなっているCanvasはマウスイベントを拾わないので、円内部だけがクリックに反応します。

無理やりな部分があまりないので転用しやすいと思います。これだけのことがXAMLだけで実現できてしまうとは、面白い技術だなと。

blog20191215-WPFTest2

XAML
<Window x:Class="RxMouseDragTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <DataTemplate x:Key="GroupListItemTemplate">
            <TextBlock Text="{Binding GroupNumber}"/>
        </DataTemplate>
        
        <DataTemplate x:Key="SpotTemplate">
            <Grid>
                <TextBlock Text="{Binding Number}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White"/>
                <Ellipse Width="{Binding Width}" Height="{Binding Height}" Fill="Transparent">
                    <Ellipse.Style>
                        <Style TargetType="{x:Type Ellipse}">
                            <Setter Property="Stroke" Value="Red"/>
                            <Setter Property="StrokeThickness" Value="3"/>
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding IsSelected,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContentControl}}" Value="true">
                                    <Setter Property="Stroke" Value="Gold"/>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding IsMouseOver,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContentControl}}" Value="true">
                                    <Setter Property="StrokeThickness" Value="6"/>
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Ellipse.Style>
                </Ellipse>
            </Grid>
        </DataTemplate>
        <Style x:Key="SpotContainerStyle" TargetType="{x:Type ContentPresenter}">
            <Setter Property="Canvas.Left" Value="{Binding Left}"/>
            <Setter Property="Canvas.Top" Value="{Binding Top}"/>
        </Style>

        <ItemsPanelTemplate x:Key="GroupPanelTemplate">
            <Canvas Background="Transparent"/>
        </ItemsPanelTemplate>        
        <DataTemplate x:Key="GroupTemplate">
            <ItemsControl
                ItemsSource="{Binding Spots}"
                ItemTemplate="{StaticResource SpotTemplate}"
                ItemContainerStyle="{StaticResource SpotContainerStyle}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </DataTemplate>
    </Window.Resources>
    
    <Grid Background="Black" ClipToBounds="True">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ListBox Name="GroupList" Grid.Column="0" ItemsSource="{Binding Groups}" ItemTemplate="{StaticResource GroupListItemTemplate}"/>
        <ListBox
            Name="ChartBase"
            Grid.Column="1"
            ItemsPanel="{StaticResource GroupPanelTemplate}"
            ItemTemplate="{StaticResource GroupTemplate}"
            ItemsSource="{Binding Groups}"
            SelectedItem="{Binding SelectedItem,ElementName=GroupList}"
            Background="{x:Null}">
        </ListBox>
    </Grid>
</Window>
コード。DataContextをセットしているだけです。
public partial class MainWindow : Window
{
    static readonly Random rnd = new Random();

    public MainWindow()
    {
        InitializeComponent();

        DataContext = new
        {
            Groups = Enumerable.Range(0, 5).Select(i => new SpotGroup(i, rnd.Next(1, 4))),
        };
    }
}

public class SpotGroup
{
    public int GroupNumber { get; private set; }
    public IEnumerable<Spot> Spots { get; private set; }

    public SpotGroup(int GroupNumber, int NumItems)
    {
        this.GroupNumber = GroupNumber;
        Spots =
            Enumerable.Range(0, NumItems)
            .Select(i => new Spot() { Number = GroupNumber })
            .ToArray();
    }
}

public class Spot
{
    static readonly Random rnd = new Random();

    public int Number { get; set; }
    public int Left { get; private set; }
    public int Top { get; private set; }
    public int Width { get; private set; }
    public int Height { get; private set; }

    public Spot()
    {
        Left = rnd.Next(0, 300);
        Top = rnd.Next(0, 250);
        Width = rnd.Next(0, 20) + 40;
        Height = rnd.Next(0, 20) + 40;
    }
}

— posted by mu at 09:34 pm   commentComment [0]  pingTrackBack [0]

WindowsでDisk is full

前回Link の続き。数時間後にまたDisk fullで不具合。MySQL以外のプログラムでもDisk fullが出たのでMySQL固有の問題ではなさそう。

このマシン、ドライブの構成は以下のようになってました。

C:¥ (NTFS)
+- ProgramData
   +- MySQL
      +- 10TBの別Volume (ReFS)

記憶域プールで作成した10TBのReFSドライブにはドライブレターを割り当てず、C:¥ProgramData¥MySQLにマウントしてました。

コマンドラインや記憶域プールマネージャーで見る限りReFSドライブにはまだ8TB以上空きがありますが、複数のプログラムでDisk fullエラーが出ている以上、Windowsが空き容量を誤認している可能性が高い。NTFSへのReFSのマウント、あまりメジャーでない構成を使ったのがいけなかったか。

というわけで、ReFSのC:¥ProgramData¥MySQLマウントは解除、ドライブレターを与えJunctionでつないで様子見することに。今度は解決してほしいなと。

ちなみにOSはWindows Server 2016 (1607)です。

[2019/7/1] Windowsバージョン訂正

[2019/7/2] ダメでした

[2019/7/3] 記憶域プールから別のディスク作って、MySQL止めて、データ全コピ。とりあえず問題起こした仮想ディスクは残しておいて…調べる暇ないだろうな(^ ^;)

— posted by mu at 12:13 pm   commentComment [0]  pingTrackBack [0]

T: Y: ALL: Online:
ThemeSwitch
  • Basic
Created in 0.0438 sec.
prev
2021.4
next
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30