aboutsummaryrefslogtreecommitdiff
path: root/gemini/gemini.go
diff options
context:
space:
mode:
Diffstat (limited to 'gemini/gemini.go')
-rw-r--r--gemini/gemini.go86
1 files changed, 86 insertions, 0 deletions
diff --git a/gemini/gemini.go b/gemini/gemini.go
new file mode 100644
index 0000000..8f4c6ef
--- /dev/null
+++ b/gemini/gemini.go
@@ -0,0 +1,86 @@
+package gemini
+
+import (
+ "crypto/tls"
+ "fmt"
+ "net/url"
+ "os"
+ "strconv"
+ "strings"
+)
+
+const GeminiNetwork = "tcp"
+const GeminiPort = 1965
+const GeminiPrefix = "gemini://"
+
+func FormatRequest(request string) []byte {
+ if !strings.HasPrefix(request, GeminiPrefix) {
+ request = GeminiPrefix + request
+ }
+ request = request + "\r\n"
+ return []byte(request)
+}
+
+type GeminiConn struct {
+ host string
+ config *tls.Config
+}
+
+func NewGeminiConn(host string, port int) *GeminiConn {
+ conf := tls.Config{
+ MinVersion: tls.VersionTLS12,
+ InsecureSkipVerify: true,
+ }
+
+ if strings.Contains(host, ":") {
+ return &GeminiConn{host, &conf}
+ } else {
+ return &GeminiConn{host + ":" + strconv.Itoa(port), &conf}
+ }
+}
+
+func NewGeminiConnFromRequest(request string, port int) (*GeminiConn, error) {
+ if !strings.HasPrefix(request, GeminiPrefix) {
+ request = GeminiPrefix + request
+ }
+
+ u, err := url.Parse(request)
+ if err != nil {
+ return nil, err
+ }
+ return NewGeminiConn(u.Host, port), nil
+}
+
+func (c *GeminiConn) Get(request []byte, out *os.File) error {
+ conn, err := tls.Dial(GeminiNetwork, c.host, c.config)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ n, err := conn.Write(request)
+ if err != nil {
+ return err
+ }
+
+ buf := make([]byte, 1024)
+
+ for {
+ n, err = conn.Read(buf)
+ if err != nil {
+ return err
+ }
+ written, err := out.Write(buf[:n])
+ if written != n {
+ return fmt.Errorf("Got %d bytes, but only wrote %d bytes", n, written)
+ }
+ if err != nil {
+ return err
+ }
+
+ if n == 0 {
+ break
+ }
+ }
+ return nil
+}