-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix #1. This commit introduces an optional ip address cache which stores the optained IPv4 and IPv6 addresses between two runs of the program. This reduces netword usage as the DNS records from netcup only need to be fetched when the current ip addresses differ between those from the last run.
- Loading branch information
Showing
5 changed files
with
316 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
package main | ||
|
||
import( | ||
"encoding/csv" | ||
"log" | ||
"io" | ||
"os" | ||
"time" | ||
) | ||
|
||
const ( | ||
defaultDir string = "/dyndns-netcup-go" | ||
defaultIPCache string = "ip.cache" | ||
) | ||
|
||
type Cache struct { | ||
location string | ||
timeout time.Duration | ||
changes bool | ||
entries []CacheEntry | ||
} | ||
|
||
type CacheEntry struct { | ||
host string | ||
ipv4 string | ||
ipv6 string | ||
} | ||
|
||
func NewCache(location string, timeout time.Duration) (*Cache, error) { | ||
if location == "" { | ||
var err error | ||
location, err = os.UserCacheDir() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
location += defaultDir | ||
|
||
if _, err := os.Stat(location); os.IsNotExist(err) { | ||
os.MkdirAll(location, 0700) | ||
} | ||
|
||
location += "/" + defaultIPCache | ||
} | ||
|
||
return &Cache{location, timeout, false, nil}, nil | ||
} | ||
|
||
func (c *Cache) Load() error { | ||
csvfile, err := os.Open(c.location) | ||
defer csvfile.Close() | ||
if err != nil { | ||
if os.IsNotExist(err) { | ||
return nil | ||
} else { | ||
return err | ||
} | ||
} | ||
|
||
fileinfo, err := csvfile.Stat() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if time.Now().Sub(fileinfo.ModTime()) > c.timeout { | ||
return nil | ||
} | ||
|
||
r := csv.NewReader(csvfile) | ||
|
||
for { | ||
record, err := r.Read() | ||
if err == io.EOF { | ||
break | ||
} | ||
if err != nil { | ||
return err | ||
} | ||
|
||
entry := CacheEntry{ | ||
host : record[0], | ||
ipv4 : record[1], | ||
ipv6 : record[2], | ||
} | ||
|
||
c.entries = append(c.entries, entry) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (c *Cache) SetIPv4(domain, host, ipv4 string) { | ||
entry := c.getEntry(domain, host) | ||
if entry == nil { | ||
newEntry := CacheEntry { | ||
host: host+domain, | ||
ipv4: ipv4, | ||
ipv6: "", | ||
} | ||
|
||
c.entries = append(c.entries, newEntry) | ||
} else { | ||
entry.ipv4 = ipv4 | ||
} | ||
|
||
c.changes = true | ||
} | ||
|
||
func (c *Cache) SetIPv6(domain, host, ipv6 string) { | ||
entry := c.getEntry(domain, host) | ||
if entry == nil { | ||
newEntry := CacheEntry { | ||
host: host+domain, | ||
ipv4: "", | ||
ipv6: ipv6, | ||
} | ||
|
||
c.entries = append(c.entries, newEntry) | ||
} else { | ||
entry.ipv6 = ipv6 | ||
} | ||
|
||
c.changes = true | ||
} | ||
|
||
func (c *Cache) GetIPv4(domain, host string) string { | ||
entry := c.getEntry(domain, host) | ||
if entry == nil { | ||
return "" | ||
} | ||
|
||
return entry.ipv4 | ||
} | ||
|
||
func (c *Cache) GetIPv6(domain, host string) string { | ||
entry := c.getEntry(domain, host) | ||
if entry == nil { | ||
return "" | ||
} | ||
|
||
return entry.ipv6 | ||
} | ||
|
||
func (c *Cache) getEntry(domain, host string) *CacheEntry { | ||
for i, entry := range c.entries { | ||
if entry.host == (host+domain) { | ||
return &c.entries[i] | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (c *Cache) Store() error { | ||
if !c.changes { | ||
return nil | ||
} | ||
|
||
csvfile, err := os.Create(c.location) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
writer := csv.NewWriter(csvfile) | ||
defer writer.Flush() | ||
|
||
for _, entry := range c.entries { | ||
err = writer.Write(entry.toArray()) | ||
log.Printf("Written %s, %s, %s to %s", entry.host, entry.ipv4, entry.ipv6, c.location) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (e *CacheEntry) toArray() []string { | ||
return []string{e.host, e.ipv4, e.ipv6} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/ | ||
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/ | ||
!_TAG_PROGRAM_AUTHOR Darren Hiebert /[email protected]/ | ||
!_TAG_PROGRAM_NAME Exuberant Ctags // | ||
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/ | ||
!_TAG_PROGRAM_VERSION 5.9~svn20110310 // | ||
AddParam netcup/request.go /^func (p Params) AddParam(key string, value interface{}) {$/;" f | ||
Client netcup/client.go /^type Client struct {$/;" t | ||
Config config.go /^type Config struct {$/;" t | ||
DNSRecord netcup/response.go /^type DNSRecord struct {$/;" t | ||
DNSRecordSet netcup/response.go /^type DNSRecordSet struct {$/;" t | ||
DNSZone netcup/response.go /^type DNSZone struct {$/;" t | ||
Domain config.go /^type Domain struct {$/;" t | ||
ErrNoApiSessionid netcup/client.go /^ ErrNoApiSessionid = errors.New("netcup: There is no ApiSessionId. Are you logged in?")$/;" v | ||
GetARecordOccurences netcup/response.go /^func (r *DNSRecordSet) GetARecordOccurences(hostname string) int {$/;" f | ||
GetRecord netcup/response.go /^func (r *DNSRecordSet) GetRecord(name, dnstype string) (*DNSRecord, bool) {$/;" f | ||
InfoDnsRecords netcup/client.go /^func (c *Client) InfoDnsRecords(domainname string) (error, *DNSRecordSet) {$/;" f | ||
InfoDnsZone netcup/client.go /^func (c *Client) InfoDnsZone(domainname string) (error, *DNSZone) {$/;" f | ||
LoadConfig config.go /^func LoadConfig(filename string) (*Config, error) {$/;" f | ||
Login netcup/client.go /^func (c *Client) Login() error {$/;" f | ||
LoginResponse netcup/response.go /^type LoginResponse struct {$/;" t | ||
NewClient netcup/client.go /^func NewClient(customernumber int, apikey, apipassword string) *Client {$/;" f | ||
NewDNSRecord netcup/response.go /^func NewDNSRecord(hostname, dnstype, destination string) *DNSRecord {$/;" f | ||
NewDNSRecordSet netcup/response.go /^func NewDNSRecordSet(records []DNSRecord) *DNSRecordSet {$/;" f | ||
NewParams netcup/request.go /^func NewParams() Params {$/;" f | ||
NewRequest netcup/request.go /^func NewRequest(action string, params *Params) *Request {$/;" f | ||
Params netcup/request.go /^type Params map[string]interface{}$/;" t | ||
Request netcup/request.go /^type Request struct {$/;" t | ||
Response netcup/response.go /^type Response struct {$/;" t | ||
SetVerbose netcup/client.go /^func SetVerbose(isVerbose bool) {$/;" f | ||
UpdateDnsRecords netcup/client.go /^func (c *Client) UpdateDnsRecords(domainname string, dnsRecordSet *DNSRecordSet) error {$/;" f | ||
UpdateDnsZone netcup/client.go /^func (c *Client) UpdateDnsZone(domainname string, dnszone *DNSZone) error {$/;" f | ||
basicAuthParams netcup/client.go /^func (c *Client) basicAuthParams(domainname string) *Params {$/;" f | ||
client main.go /^ client *netcup.Client$/;" v | ||
config main.go /^ config *Config$/;" v | ||
configFile main.go /^ configFile string$/;" v | ||
configUsage main.go /^ configUsage = "Specify location of the config file"$/;" c | ||
configureARecord main.go /^func configureARecord(host string, records *netcup.DNSRecordSet) *netcup.DNSRecord {$/;" f | ||
configureDomains main.go /^func configureDomains() {$/;" f | ||
configureRecords main.go /^func configureRecords(domain Domain) {$/;" f | ||
configureZone main.go /^func configureZone(domain Domain) {$/;" f | ||
defaultConfigFile main.go /^ defaultConfigFile = "config.yml"$/;" c | ||
do ip.go /^func do(url string) (string, error) {$/;" f | ||
do netcup/client.go /^func (c *Client) do(req *Request) (*Response, error) {$/;" f | ||
getFormattedError netcup/response.go /^func (r *Response) getFormattedError() string {$/;" f | ||
getFormattedStatus netcup/response.go /^func (r *Response) getFormattedStatus() string {$/;" f | ||
getIPv4 ip.go /^func getIPv4() (string, error) {$/;" f | ||
getIPv6 ip.go /^func getIPv6() (string, error) {$/;" f | ||
init main.go /^func init() {$/;" f | ||
ipv4 main.go /^ ipv4 string$/;" v | ||
ipv6 main.go /^ ipv6 string$/;" v | ||
isError netcup/response.go /^func (r *Response) isError() bool {$/;" f | ||
isSuccess netcup/response.go /^func (r *Response) isSuccess() bool {$/;" f | ||
loadIPv4 main.go /^func loadIPv4() {$/;" f | ||
loadIPv6 main.go /^func loadIPv6() {$/;" f | ||
logInfo main.go /^func logInfo(msg string, v ...interface{}) {$/;" f | ||
logInfo netcup/client.go /^func logInfo(msg string, v ...interface{}) {$/;" f | ||
login main.go /^func login() {$/;" f | ||
main config.go /^package main$/;" p | ||
main ip.go /^package main$/;" p | ||
main main.go /^func main() {$/;" f | ||
main main.go /^package main$/;" p | ||
netcup netcup/client.go /^package netcup$/;" p | ||
netcup netcup/request.go /^package netcup$/;" p | ||
netcup netcup/response.go /^package netcup$/;" p | ||
url netcup/client.go /^ url = "https:\/\/ccp.netcup.net\/run\/webservice\/servers\/endpoint.php?JSON"$/;" c | ||
verbose main.go /^ verbose bool$/;" v | ||
verbose netcup/client.go /^ verbose = false$/;" v | ||
verboseUsage main.go /^ verboseUsage = "Use verbose output"$/;" c |