@@ -3,14 +3,19 @@ package ip
3
3
import (
4
4
"database/sql/driver"
5
5
"encoding/json"
6
+ "errors"
6
7
"fmt"
7
- "net/netip"
8
8
)
9
9
10
- type IPv4 string
10
+ type IP struct {
11
+ v4 IPv4
12
+ v6 IPv6
13
+ raw string
14
+ isV6 bool
15
+ }
11
16
12
17
// Value implementation of driver.Valuer
13
- func (ip IPv4 ) Value () (value driver.Value , err error ) {
18
+ func (ip IP ) Value () (value driver.Value , err error ) {
14
19
if err = ip .Validate (); err != nil {
15
20
return nil , err
16
21
}
@@ -19,24 +24,34 @@ func (ip IPv4) Value() (value driver.Value, err error) {
19
24
}
20
25
21
26
// Validate implementation of ozzo-validation Validate interface
22
- func (ip IPv4 ) Validate () error {
23
- _ , err : = FromString (ip .String ())
27
+ func (ip IP ) Validate () error {
28
+ var fromStringIP , err = FromString (ip .String ())
24
29
if err != nil {
25
- return fmt .Errorf ("'%s' is not an valid IPv4 address, err: %w" , ip , err )
30
+ return fmt .Errorf ("'%s' is not an valid IP address, err: %w" , ip , err )
26
31
}
27
32
28
- return nil
33
+ if fromStringIP .raw == ip .raw &&
34
+ fromStringIP .isV6 == ip .isV6 &&
35
+ fromStringIP .v4 == ip .v4 &&
36
+ fromStringIP .v6 == ip .v6 {
37
+ return nil
38
+ }
39
+
40
+ return errors .New (`IP inconsistency error` )
29
41
}
30
42
31
43
// UnmarshalJSON unmarshall implementation for IP
32
- func (ip * IPv4 ) UnmarshalJSON (data []byte ) error {
33
- var str string
34
- if err := json .Unmarshal (data , & str ); err != nil {
44
+ func (ip * IP ) UnmarshalJSON (data []byte ) error {
45
+ var (
46
+ str string
47
+ err error
48
+ )
49
+ if err = json .Unmarshal (data , & str ); err != nil {
35
50
return err
36
51
}
37
52
38
- value := IPv4 ( str )
39
- if err := value . Validate ( ); err != nil {
53
+ var value IP
54
+ if value , err = FromString ( str ); err != nil && value . Validate () != nil {
40
55
return err
41
56
}
42
57
@@ -45,24 +60,50 @@ func (ip *IPv4) UnmarshalJSON(data []byte) error {
45
60
return nil
46
61
}
47
62
63
+ // MarshalJSON marshall implementation for IP
64
+ func (ip IP ) MarshalJSON () ([]byte , error ) {
65
+ return json .Marshal (ip .raw )
66
+ }
67
+
48
68
// String implementation of Stringer interface
49
- func (ip IPv4 ) String () string {
50
- return string ( ip )
69
+ func (ip IP ) String () string {
70
+ return ip . raw
51
71
}
52
72
53
- func FromString (value string ) (IPv4 , error ) {
73
+ func (ip IP ) IPv4 () IPv4 {
74
+ return ip .v4
75
+ }
76
+
77
+ func (ip IP ) IPv6 () IPv6 {
78
+ return ip .v6
79
+ }
80
+
81
+ func (ip IP ) IsIPv6 () bool {
82
+ return ip .isV6
83
+ }
84
+
85
+ func FromString (value string ) (IP , error ) {
54
86
if value == "" {
55
- return "" , fmt .Errorf ("empty value" )
87
+ return IP {} , fmt .Errorf ("empty value" )
56
88
}
57
89
58
- var addr , err = netip .ParseAddr (value )
59
- if err != nil {
60
- return "" , err
90
+ var v4Addr , err = V4FromString (value )
91
+ if err == nil {
92
+ return IP {
93
+ v4 : v4Addr ,
94
+ isV6 : false ,
95
+ raw : value ,
96
+ }, nil
61
97
}
62
98
63
- if ! addr .Is4 () {
64
- return "" , fmt .Errorf ("not an IPv4 address" )
99
+ var v6Addr IPv6
100
+ if v6Addr , err = V6FromString (value ); err == nil {
101
+ return IP {
102
+ v6 : v6Addr ,
103
+ isV6 : true ,
104
+ raw : value ,
105
+ }, nil
65
106
}
66
107
67
- return IPv4 ( addr . String ()), nil
108
+ return IP {}, errors . New ( "value isn't fit neither v4 nor v6 IP" )
68
109
}
0 commit comments