forked from lug/matterbridge
		
	Compare commits
	
		
			32 Commits
		
	
	
		
			v1.14.0-rc
			...
			v1.14.1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 858e16d34f | ||
|   | a60e62efb1 | ||
|   | 97f9d4be67 | ||
|   | fa4eec41f7 | ||
|   | 77516c97db | ||
|   | cba01f0865 | ||
|   | 8b754017ca | ||
|   | a27600046e | ||
|   | fb2667631d | ||
|   | b638f7037a | ||
|   | 74699a8262 | ||
|   | eabf2a4582 | ||
|   | 325d62b41c | ||
|   | e955a056e2 | ||
|   | 723f8c5fd5 | ||
|   | a16137f53f | ||
|   | d60b8b97f9 | ||
|   | 7b0bc51183 | ||
|   | 53aa076555 | ||
|   | f57370f33a | ||
|   | c557d51b6f | ||
|   | df3fdc26a0 | ||
|   | af00c34aac | ||
|   | 120bf39f55 | ||
|   | 26a7e35f27 | ||
|   | d44d2a5f00 | ||
|   | 7f1d86b338 | ||
|   | d8816280f0 | ||
|   | b09a73040f | ||
|   | 740b5f2602 | ||
|   | 96841c70c7 | ||
|   | f92735d35d | 
| @@ -158,7 +158,6 @@ linters-settings: | ||||
|       - regexpMust | ||||
|       - singleCaseSwitch | ||||
|       - sloppyLen | ||||
|       - sloppyReassign | ||||
|       - switchTrue | ||||
|       - typeSwitchVar | ||||
|       - typeUnparen | ||||
|   | ||||
							
								
								
									
										34
									
								
								.goreleaser.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								.goreleaser.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| release: | ||||
|   prerelease: auto | ||||
|   name_template: "{{.ProjectName}} v{{.Version}}" | ||||
|  | ||||
| builds: | ||||
| - env: | ||||
|     - CGO_ENABLED=0 | ||||
|   goos: | ||||
|     - freebsd | ||||
|     - windows | ||||
|     - darwin | ||||
|     - linux | ||||
|     - dragonfly | ||||
|     - netbsd | ||||
|     - openbsd | ||||
|   goarch: | ||||
|     - amd64 | ||||
|     - arm | ||||
|     - arm64 | ||||
|     - 386 | ||||
|   ldflags: | ||||
|     - -s -w -X main.githash={{.ShortCommit}} | ||||
|  | ||||
| archive: | ||||
|   name_template: "{{ .Binary }}-{{ .Version }}-{{ .Os }}-{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}" | ||||
|   format: binary | ||||
|   files: | ||||
|     - none* | ||||
|   replacements: | ||||
|     386: 32bit | ||||
|     amd64: 64bit | ||||
|  | ||||
| checksum: | ||||
|   name_template: 'checksums.txt' | ||||
							
								
								
									
										18
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -12,6 +12,7 @@ git: | ||||
| env: | ||||
|   global: | ||||
|     - GOOS=linux GOARCH=amd64 | ||||
|     - GO111MODULE=on | ||||
|     - GOLANGCI_VERSION="v1.14.0" | ||||
|  | ||||
| matrix: | ||||
| @@ -36,10 +37,17 @@ before_script: | ||||
|   - ./cc-test-reporter before-build | ||||
|  | ||||
| script: | ||||
|   # Ensure that the module files are being kept correctly and that vendored dependencies are up-to-date. | ||||
|   - go mod tidy | ||||
|   - go mod vendor | ||||
|   - git diff --exit-code --quiet || (echo "Please run 'go mod tidy' to clean up the 'go.mod' and 'go.sum' files."; false) | ||||
|  | ||||
|   # Run the linter. | ||||
|   - golangci-lint run | ||||
|  | ||||
|   # Run all the tests with the race detector and generate coverage. | ||||
|   - go test -v -race -coverprofile c.out ./... | ||||
|  | ||||
|   # Run the build script to generate the necessary binaries and images. | ||||
|   - /bin/bash ci/bintray.sh | ||||
|  | ||||
| @@ -47,11 +55,21 @@ after_script: | ||||
|   # Upload test coverage to CodeClimate. | ||||
|   - ./cc-test-reporter after-build --exit-code ${TRAVIS_TEST_RESULT} | ||||
|  | ||||
| branches: | ||||
|   only: | ||||
|     - master | ||||
|  | ||||
| deploy: | ||||
|   on: | ||||
|      all_branches: true | ||||
|   provider: bintray | ||||
|   on: | ||||
|     all_branches: true | ||||
|   edge: | ||||
|     branch: v1.8.47 | ||||
|   file: ci/deploy.json | ||||
|   user: 42wim | ||||
|   on: | ||||
|      all_branches: true | ||||
|   key: | ||||
|      secure: "CeXXe6JOmt7HYR81MdWLua0ltQHhDdkIeRGBFbgd7hkb1wi8eF9DgpAcQrTso8NIlHNZmSAP46uhFgsRvkuezzX0ygalZ7DCJyAyn3sAMEh+UQSHV1WGThRehTtidqRGjetzsIGSwdrJOWil+XTfbO1Z8DGzfakhSuAZka8CM4BAoe3YeP9rYK8h+84x0GHfczvsLtXZ3mWLvQuwe4pK6+ItBCUg0ae7O7ZUpWHy0xQQkkWztY/6RAzXfaG7DuGjIw+20fhx3WOXRNpHCtZ6Bc3qERCpk0s1HhlQWlrN9wDaFTBWYwlvSnNgvxxMbNXJ6RrRJ0l0bA7FUswYwyroxhzrGLdzWDg8dHaQkypocngdalfhpsnoO9j3ApJhomUFJ3UoEq5nOGRUrKn8MPi+dP0zE4kNQ3e4VNa1ufNrvfpWolMg3xh8OXuhQdD5wIM5zFAbRJLqWSCVAjPq4DDPecmvXBOlIial7oa312lN5qnBnUjvAcxszZ+FUyDHT1Grxzna4tMwxY9obPzZUzm7359AOCCwIQFVB8GLqD2nwIstcXS0zGRz+fhviPipHuBa02q5bGUZwmkvrSNab0s8Jo7pCrel2Rz3nWPKaiCfq2WjbW1CLheSMkOQrjsdUd1hhbqNWFPUjJPInTc77NAKCfm5runv5uyowRLh4NNd0sI=" | ||||
|   | ||||
							
								
								
									
										10
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								README.md
									
									
									
									
									
								
							| @@ -88,6 +88,7 @@ | ||||
| * [Minecraft](https://github.com/elytra/MatterLink) | ||||
| * [Reddit](https://github.com/bonehurtingjuice/mattereddit) | ||||
| * [Facebook messenger](https://github.com/VictorNine/fbridge) | ||||
| * [Discourse](https://github.com/DeclanHoare/matterbabble) | ||||
|  | ||||
| ### API | ||||
| The API is very basic at the moment.    | ||||
| @@ -99,6 +100,7 @@ Used by the projects below. Feel free to make a PR to add your project to this l | ||||
| * [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot) | ||||
| * [Mattereddit](https://github.com/bonehurtingjuice/mattereddit) (Reddit chat support) | ||||
| * [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support) | ||||
| * [matterbabble](https://github.com/DeclanHoare/matterbabble) (Discourse support) | ||||
|  | ||||
| ## Chat with us | ||||
|  | ||||
| @@ -121,7 +123,7 @@ See https://github.com/42wim/matterbridge/wiki | ||||
|  | ||||
| ## Installing | ||||
| ### Binaries | ||||
| * Latest stable release [v1.13.1](https://github.com/42wim/matterbridge/releases/latest) | ||||
| * Latest stable release [v1.14.1](https://github.com/42wim/matterbridge/releases/latest) | ||||
| * Development releases (follows master) can be downloaded [here](https://dl.bintray.com/42wim/nightly/) | ||||
|  | ||||
| ### Packages | ||||
| @@ -237,10 +239,6 @@ See [changelog.md](https://github.com/42wim/matterbridge/blob/master/changelog.m | ||||
|  | ||||
| See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ) | ||||
|  | ||||
| Want to tip ? | ||||
| * eth: 0xb3f9b5387c66ad6be892bcb7bbc67862f3abc16f | ||||
| * btc: 1N7cKHj5SfqBHBzDJ6kad4BzeqUBBS2zhs | ||||
|  | ||||
| ## Related projects | ||||
| * [FOSSRIT/infrastructure - roles/matterbridge](https://github.com/FOSSRIT/infrastructure/tree/master/roles/matterbridge) (Ansible role used to automate deployments of Matterbridge) | ||||
| * [matterbridge autoconfig](https://github.com/patcon/matterbridge-autoconfig) | ||||
| @@ -251,6 +249,8 @@ Want to tip ? | ||||
| * [mattermost-plugin](https://github.com/matterbridge/mattermost-plugin) - Run matterbridge as a plugin in mattermost | ||||
| * [pyCord](https://github.com/NikkyAI/pyCord) (crossplatform chatbot) | ||||
| * [fbridge](https://github.com/VictorNine/fbridge) (Facebook messenger support) | ||||
| * [isla](https://github.com/alphachung/isla) (Bot for Discord-Telegram groups used alongside matterbridge) | ||||
| * [matterbabble](https://github.com/DeclanHoare/matterbabble) (Connect Discourse threads to Matterbridge) | ||||
|  | ||||
| ## Articles | ||||
| * [matterbridge on kubernetes](https://medium.freecodecamp.org/using-kubernetes-to-deploy-a-chat-gateway-or-when-technology-works-like-its-supposed-to-a169a8cd69a3) | ||||
|   | ||||
| @@ -93,6 +93,7 @@ type Protocol struct { | ||||
| 	MediaDownloadSize      int    // all protocols | ||||
| 	MediaServerDownload    string | ||||
| 	MediaServerUpload      string | ||||
| 	MediaConvertWebPToPNG  bool       // telegram | ||||
| 	MessageDelay           int        // IRC, time in millisecond to wait between messages | ||||
| 	MessageFormat          string     // telegram | ||||
| 	MessageLength          int        // IRC, max length of a message allowed | ||||
|   | ||||
| @@ -246,7 +246,7 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) { | ||||
| 			b.Log.Debugf("Setting webhook channel to \"%s\"", msg.Channel) | ||||
| 			_, err := b.c.WebhookEdit(wID, "", "", channelID) | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("Could not set webhook channel: %v", err) | ||||
| 				b.Log.Errorf("Could not set webhook channel: %s", err) | ||||
| 				return "", err | ||||
| 			} | ||||
| 		} | ||||
| @@ -278,7 +278,7 @@ func (b *Bdiscord) Send(msg config.Message) (string, error) { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			rmsg.Text = helper.ClipMessage(rmsg.Text, MessageLength) | ||||
| 			if _, err := b.c.ChannelMessageSend(channelID, rmsg.Username+rmsg.Text); err != nil { | ||||
| 				b.Log.Errorf("Could not send message %#v: %v", rmsg, err) | ||||
| 				b.Log.Errorf("Could not send message %#v: %s", rmsg, err) | ||||
| 			} | ||||
| 		} | ||||
| 		// check if we have files to upload (from slack, telegram or mattermost) | ||||
| @@ -360,7 +360,7 @@ func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (stri | ||||
| 		} | ||||
| 		_, err = b.c.ChannelMessageSendComplex(channelID, &m) | ||||
| 		if err != nil { | ||||
| 			return "", fmt.Errorf("file upload failed: %#v", err) | ||||
| 			return "", fmt.Errorf("file upload failed: %s", err) | ||||
| 		} | ||||
| 	} | ||||
| 	return "", nil | ||||
|   | ||||
| @@ -36,7 +36,7 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat | ||||
| 		return | ||||
| 	} | ||||
| 	// if using webhooks, do not relay if it's ours | ||||
| 	if b.useWebhook() && m.Author.Bot && b.isWebhookID(m.Author.ID) { | ||||
| 	if b.useWebhook() && m.Author.Bot { // && b.isWebhookID(m.Author.ID) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -25,7 +25,7 @@ func (b *Bdiscord) getNick(user *discordgo.User) string { | ||||
| 	// If we didn't find nick, search for it. | ||||
| 	member, err := b.c.GuildMember(b.guildID, user.ID) | ||||
| 	if err != nil { | ||||
| 		b.Log.Warnf("Failed to fetch information for member %#v: %#v", user, err) | ||||
| 		b.Log.Warnf("Failed to fetch information for member %#v: %s", user, err) | ||||
| 		return user.Username | ||||
| 	} else if member == nil { | ||||
| 		b.Log.Warnf("Got no information for member %#v", user) | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package helper | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"image/png" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"regexp" | ||||
| @@ -10,6 +11,8 @@ import ( | ||||
| 	"time" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"golang.org/x/image/webp" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| 	"gitlab.com/golang-commonmark/markdown" | ||||
| @@ -175,5 +178,24 @@ func ClipMessage(text string, length int) string { | ||||
|  | ||||
| func ParseMarkdown(input string) string { | ||||
| 	md := markdown.New(markdown.XHTMLOutput(true), markdown.Breaks(true)) | ||||
| 	return (md.RenderToString([]byte(input))) | ||||
| 	res := md.RenderToString([]byte(input)) | ||||
| 	res = strings.TrimPrefix(res, "<p>") | ||||
| 	res = strings.TrimSuffix(res, "</p>\n") | ||||
| 	return res | ||||
| } | ||||
|  | ||||
| // ConvertWebPToPNG convert input data (which should be WebP format to PNG format) | ||||
| func ConvertWebPToPNG(data *[]byte) error { | ||||
| 	r := bytes.NewReader(*data) | ||||
| 	m, err := webp.Decode(r) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	var output []byte | ||||
| 	w := bytes.NewBuffer(output) | ||||
| 	if err := png.Encode(w, m); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	*data = w.Bytes() | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| package helper | ||||
|  | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| @@ -103,3 +105,22 @@ func TestGetSubLines(t *testing.T) { | ||||
| 		assert.Equalf(t, testcase.nonSplitOutput, nonSplitLines, "'%s' testcase should give expected lines without splitting.", testname) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestConvertWebPToPNG(t *testing.T) { | ||||
| 	if os.Getenv("LOCAL_TEST") == "" { | ||||
| 		t.Skip() | ||||
| 	} | ||||
| 	input, err := ioutil.ReadFile("test.webp") | ||||
| 	if err != nil { | ||||
| 		t.Fail() | ||||
| 	} | ||||
| 	d := &input | ||||
| 	err = ConvertWebPToPNG(d) | ||||
| 	if err != nil { | ||||
| 		t.Fail() | ||||
| 	} | ||||
| 	err = ioutil.WriteFile("test.png", *d, 0644) | ||||
| 	if err != nil { | ||||
| 		t.Fail() | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -40,6 +40,11 @@ func (b *Brocketchat) handleRocketHook(messages chan *config.Message) { | ||||
|  | ||||
| func (b *Brocketchat) handleRocketClient(messages chan *config.Message) { | ||||
| 	for message := range b.messageChan { | ||||
| 		// skip messages with same ID, apparently messages get duplicated for an unknown reason | ||||
| 		if _, ok := b.cache.Get(message.ID); ok { | ||||
| 			continue | ||||
| 		} | ||||
| 		b.cache.Add(message.ID, true) | ||||
| 		b.Log.Debugf("message %#v", message) | ||||
| 		m := message | ||||
| 		if b.skipMessage(&m) { | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package brocketchat | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| @@ -9,16 +10,18 @@ import ( | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	"github.com/42wim/matterbridge/hook/rockethook" | ||||
| 	"github.com/42wim/matterbridge/matterhook" | ||||
| 	lru "github.com/hashicorp/golang-lru" | ||||
| 	"github.com/matterbridge/Rocket.Chat.Go.SDK/models" | ||||
| 	"github.com/matterbridge/Rocket.Chat.Go.SDK/realtime" | ||||
| 	"github.com/matterbridge/Rocket.Chat.Go.SDK/rest" | ||||
| ) | ||||
|  | ||||
| type Brocketchat struct { | ||||
| 	mh *matterhook.Client | ||||
| 	rh *rockethook.Client | ||||
| 	c  *realtime.Client | ||||
| 	r  *rest.Client | ||||
| 	mh    *matterhook.Client | ||||
| 	rh    *rockethook.Client | ||||
| 	c     *realtime.Client | ||||
| 	r     *rest.Client | ||||
| 	cache *lru.Cache | ||||
| 	*bridge.Config | ||||
| 	messageChan chan models.Message | ||||
| 	channelMap  map[string]string | ||||
| @@ -27,9 +30,16 @@ type Brocketchat struct { | ||||
| } | ||||
|  | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Brocketchat{Config: cfg} | ||||
| 	b.messageChan = make(chan models.Message) | ||||
| 	b.channelMap = make(map[string]string) | ||||
| 	newCache, err := lru.New(100) | ||||
| 	if err != nil { | ||||
| 		cfg.Log.Fatalf("Could not create LRU cache for rocketchat bridge: %v", err) | ||||
| 	} | ||||
| 	b := &Brocketchat{ | ||||
| 		Config:      cfg, | ||||
| 		messageChan: make(chan models.Message), | ||||
| 		channelMap:  make(map[string]string), | ||||
| 		cache:       newCache, | ||||
| 	} | ||||
| 	b.Log.Debugf("enabling rocketchat") | ||||
| 	return b | ||||
| } | ||||
| @@ -76,14 +86,14 @@ func (b *Brocketchat) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	if b.c == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	id, err := b.c.GetChannelId(channel.Name) | ||||
| 	id, err := b.c.GetChannelId(strings.TrimPrefix(channel.Name, "#")) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	b.Lock() | ||||
| 	b.channelMap[id] = channel.Name | ||||
| 	b.Unlock() | ||||
| 	mychannel := &models.Channel{ID: id, Name: channel.Name} | ||||
| 	mychannel := &models.Channel{ID: id, Name: strings.TrimPrefix(channel.Name, "#")} | ||||
| 	if err := b.c.JoinChannel(id); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| @@ -94,6 +104,8 @@ func (b *Brocketchat) JoinChannel(channel config.ChannelInfo) error { | ||||
| } | ||||
|  | ||||
| func (b *Brocketchat) Send(msg config.Message) (string, error) { | ||||
| 	// strip the # if people has set this | ||||
| 	msg.Channel = strings.TrimPrefix(msg.Channel, "#") | ||||
| 	channel := &models.Channel{ID: b.getChannelID(msg.Channel), Name: msg.Channel} | ||||
|  | ||||
| 	// Delete message | ||||
| @@ -122,6 +134,8 @@ func (b *Brocketchat) Send(msg config.Message) (string, error) { | ||||
| 	// Upload a file if it exists | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			// strip the # if people has set this | ||||
| 			rmsg.Channel = strings.TrimPrefix(rmsg.Channel, "#") | ||||
| 			smsg := &models.Message{ | ||||
| 				RoomID: b.getChannelID(rmsg.Channel), | ||||
| 				Msg:    rmsg.Username + rmsg.Text, | ||||
|   | ||||
| @@ -34,7 +34,7 @@ func (b *Bslack) handleSlack() { | ||||
| 		message.Text = html.UnescapeString(message.Text) | ||||
|  | ||||
| 		// Add the avatar | ||||
| 		message.Avatar = b.getAvatar(message.UserID) | ||||
| 		message.Avatar = b.users.getAvatar(message.UserID) | ||||
|  | ||||
| 		b.Log.Debugf("<= Message is %#v", message) | ||||
| 		b.Remote <- *message | ||||
| @@ -75,20 +75,17 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) { | ||||
| 			// When we join a channel we update the full list of users as | ||||
| 			// well as the information for the channel that we joined as this | ||||
| 			// should now tell that we are a member of it. | ||||
| 			b.channelsMutex.Lock() | ||||
| 			b.channelsByID[ev.Channel.ID] = &ev.Channel | ||||
| 			b.channelsByName[ev.Channel.Name] = &ev.Channel | ||||
| 			b.channelsMutex.Unlock() | ||||
| 			b.channels.registerChannel(ev.Channel) | ||||
| 		case *slack.ConnectedEvent: | ||||
| 			b.si = ev.Info | ||||
| 			b.populateChannels(true) | ||||
| 			b.populateUsers(true) | ||||
| 			b.channels.populateChannels(true) | ||||
| 			b.users.populateUsers(true) | ||||
| 		case *slack.InvalidAuthEvent: | ||||
| 			b.Log.Fatalf("Invalid Token %#v", ev) | ||||
| 		case *slack.ConnectionErrorEvent: | ||||
| 			b.Log.Errorf("Connection failed %#v %#v", ev.Error(), ev.ErrorObj) | ||||
| 		case *slack.MemberJoinedChannelEvent: | ||||
| 			b.populateUser(ev.User) | ||||
| 			b.users.populateUser(ev.User) | ||||
| 		case *slack.LatencyReport: | ||||
| 			continue | ||||
| 		default: | ||||
| @@ -210,7 +207,7 @@ func (b *Bslack) handleStatusEvent(ev *slack.MessageEvent, rmsg *config.Message) | ||||
| 		rmsg.Username = sSystemUser | ||||
| 		rmsg.Event = config.EventJoinLeave | ||||
| 	case sChannelTopic, sChannelPurpose: | ||||
| 		b.populateChannels(false) | ||||
| 		b.channels.populateChannels(false) | ||||
| 		rmsg.Event = config.EventTopicChange | ||||
| 	case sMessageChanged: | ||||
| 		rmsg.Text = ev.SubMessage.Text | ||||
| @@ -266,7 +263,7 @@ func (b *Bslack) handleAttachments(ev *slack.MessageEvent, rmsg *config.Message) | ||||
| } | ||||
|  | ||||
| func (b *Bslack) handleTypingEvent(ev *slack.UserTypingEvent) (*config.Message, error) { | ||||
| 	channelInfo, err := b.getChannelByID(ev.Channel) | ||||
| 	channelInfo, err := b.channels.getChannelByID(ev.Channel) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -316,36 +313,7 @@ func (b *Bslack) handleGetChannelMembers(rmsg *config.Message) bool { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	cMembers := config.ChannelMembers{} | ||||
|  | ||||
| 	b.channelMembersMutex.RLock() | ||||
|  | ||||
| 	for channelID, members := range b.channelMembers { | ||||
| 		for _, member := range members { | ||||
| 			channelName := "" | ||||
| 			userName := "" | ||||
| 			userNick := "" | ||||
| 			user := b.getUser(member) | ||||
| 			if user != nil { | ||||
| 				userName = user.Name | ||||
| 				userNick = user.Profile.DisplayName | ||||
| 			} | ||||
| 			channel, _ := b.getChannelByID(channelID) | ||||
| 			if channel != nil { | ||||
| 				channelName = channel.Name | ||||
| 			} | ||||
| 			cMember := config.ChannelMember{ | ||||
| 				Username:    userName, | ||||
| 				Nick:        userNick, | ||||
| 				UserID:      member, | ||||
| 				ChannelID:   channelID, | ||||
| 				ChannelName: channelName, | ||||
| 			} | ||||
| 			cMembers = append(cMembers, cMember) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	b.channelMembersMutex.RUnlock() | ||||
| 	cMembers := b.channels.getChannelMembers(b.users) | ||||
|  | ||||
| 	extra := make(map[string][]interface{}) | ||||
| 	extra[config.EventGetChannelMembers] = append(extra[config.EventGetChannelMembers], cMembers) | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| package bslack | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
| @@ -9,225 +8,14 @@ import ( | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/nlopes/slack" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| func (b *Bslack) getUser(id string) *slack.User { | ||||
| 	b.usersMutex.RLock() | ||||
| 	user, ok := b.users[id] | ||||
| 	b.usersMutex.RUnlock() | ||||
| 	if ok { | ||||
| 		return user | ||||
| 	} | ||||
| 	b.populateUser(id) | ||||
| 	b.usersMutex.RLock() | ||||
| 	defer b.usersMutex.RUnlock() | ||||
|  | ||||
| 	return b.users[id] | ||||
| } | ||||
|  | ||||
| func (b *Bslack) getUsername(id string) string { | ||||
| 	if user := b.getUser(id); user != nil { | ||||
| 		if user.Profile.DisplayName != "" { | ||||
| 			return user.Profile.DisplayName | ||||
| 		} | ||||
| 		return user.Name | ||||
| 	} | ||||
| 	b.Log.Warnf("Could not find user with ID '%s'", id) | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (b *Bslack) getAvatar(id string) string { | ||||
| 	if user := b.getUser(id); user != nil { | ||||
| 		return user.Profile.Image48 | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (b *Bslack) getChannel(channel string) (*slack.Channel, error) { | ||||
| 	if strings.HasPrefix(channel, "ID:") { | ||||
| 		return b.getChannelByID(strings.TrimPrefix(channel, "ID:")) | ||||
| 	} | ||||
| 	return b.getChannelByName(channel) | ||||
| } | ||||
|  | ||||
| func (b *Bslack) getChannelByName(name string) (*slack.Channel, error) { | ||||
| 	return b.getChannelBy(name, b.channelsByName) | ||||
| } | ||||
|  | ||||
| func (b *Bslack) getChannelByID(ID string) (*slack.Channel, error) { | ||||
| 	return b.getChannelBy(ID, b.channelsByID) | ||||
| } | ||||
|  | ||||
| func (b *Bslack) getChannelBy(lookupKey string, lookupMap map[string]*slack.Channel) (*slack.Channel, error) { | ||||
| 	b.channelsMutex.RLock() | ||||
| 	defer b.channelsMutex.RUnlock() | ||||
|  | ||||
| 	if channel, ok := lookupMap[lookupKey]; ok { | ||||
| 		return channel, nil | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("%s: channel %s not found", b.Account, lookupKey) | ||||
| } | ||||
|  | ||||
| const minimumRefreshInterval = 10 * time.Second | ||||
|  | ||||
| func (b *Bslack) populateUser(userID string) { | ||||
| 	b.usersMutex.RLock() | ||||
| 	_, exists := b.users[userID] | ||||
| 	b.usersMutex.RUnlock() | ||||
| 	if exists { | ||||
| 		// already in cache | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	user, err := b.sc.GetUserInfo(userID) | ||||
| 	if err != nil { | ||||
| 		b.Log.Debugf("GetUserInfo failed for %v: %v", userID, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	b.usersMutex.Lock() | ||||
| 	b.users[userID] = user | ||||
| 	b.usersMutex.Unlock() | ||||
| } | ||||
|  | ||||
| func (b *Bslack) populateUsers(wait bool) { | ||||
| 	b.refreshMutex.Lock() | ||||
| 	if !wait && (time.Now().Before(b.earliestUserRefresh) || b.refreshInProgress) { | ||||
| 		b.Log.Debugf("Not refreshing user list as it was done less than %v ago.", | ||||
| 			minimumRefreshInterval) | ||||
| 		b.refreshMutex.Unlock() | ||||
|  | ||||
| 		return | ||||
| 	} | ||||
| 	for b.refreshInProgress { | ||||
| 		b.refreshMutex.Unlock() | ||||
| 		time.Sleep(time.Second) | ||||
| 		b.refreshMutex.Lock() | ||||
| 	} | ||||
| 	b.refreshInProgress = true | ||||
| 	b.refreshMutex.Unlock() | ||||
|  | ||||
| 	newUsers := map[string]*slack.User{} | ||||
| 	pagination := b.sc.GetUsersPaginated(slack.GetUsersOptionLimit(200)) | ||||
| 	count := 0 | ||||
| 	for { | ||||
| 		var err error | ||||
| 		pagination, err = pagination.Next(context.Background()) | ||||
| 		time.Sleep(time.Second) | ||||
| 		if err != nil { | ||||
| 			if pagination.Done(err) { | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			if err = b.handleRateLimit(err); err != nil { | ||||
| 				b.Log.Errorf("Could not retrieve users: %#v", err) | ||||
| 				return | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		for i := range pagination.Users { | ||||
| 			newUsers[pagination.Users[i].ID] = &pagination.Users[i] | ||||
| 		} | ||||
| 		b.Log.Debugf("getting %d users", len(pagination.Users)) | ||||
| 		count++ | ||||
| 		// more > 2000 users, slack will complain and ratelimit. break | ||||
| 		if count > 10 { | ||||
| 			b.Log.Info("Large slack detected > 2000 users, skipping loading complete userlist.") | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	b.usersMutex.Lock() | ||||
| 	defer b.usersMutex.Unlock() | ||||
| 	b.users = newUsers | ||||
|  | ||||
| 	b.refreshMutex.Lock() | ||||
| 	defer b.refreshMutex.Unlock() | ||||
| 	b.earliestUserRefresh = time.Now().Add(minimumRefreshInterval) | ||||
| 	b.refreshInProgress = false | ||||
| } | ||||
|  | ||||
| func (b *Bslack) populateChannels(wait bool) { | ||||
| 	b.refreshMutex.Lock() | ||||
| 	if !wait && (time.Now().Before(b.earliestChannelRefresh) || b.refreshInProgress) { | ||||
| 		b.Log.Debugf("Not refreshing channel list as it was done less than %v seconds ago.", | ||||
| 			minimumRefreshInterval) | ||||
| 		b.refreshMutex.Unlock() | ||||
| 		return | ||||
| 	} | ||||
| 	for b.refreshInProgress { | ||||
| 		b.refreshMutex.Unlock() | ||||
| 		time.Sleep(time.Second) | ||||
| 		b.refreshMutex.Lock() | ||||
| 	} | ||||
| 	b.refreshInProgress = true | ||||
| 	b.refreshMutex.Unlock() | ||||
|  | ||||
| 	newChannelsByID := map[string]*slack.Channel{} | ||||
| 	newChannelsByName := map[string]*slack.Channel{} | ||||
| 	newChannelMembers := make(map[string][]string) | ||||
|  | ||||
| 	// We only retrieve public and private channels, not IMs | ||||
| 	// and MPIMs as those do not have a channel name. | ||||
| 	queryParams := &slack.GetConversationsParameters{ | ||||
| 		ExcludeArchived: "true", | ||||
| 		Types:           []string{"public_channel,private_channel"}, | ||||
| 	} | ||||
| 	for { | ||||
| 		channels, nextCursor, err := b.sc.GetConversations(queryParams) | ||||
| 		if err != nil { | ||||
| 			if err = b.handleRateLimit(err); err != nil { | ||||
| 				b.Log.Errorf("Could not retrieve channels: %#v", err) | ||||
| 				return | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		for i := range channels { | ||||
| 			newChannelsByID[channels[i].ID] = &channels[i] | ||||
| 			newChannelsByName[channels[i].Name] = &channels[i] | ||||
| 			// also find all the members in every channel | ||||
| 			// comment for now, issues on big slacks | ||||
| 			/* | ||||
| 				members, err := b.getUsersInConversation(channels[i].ID) | ||||
| 				if err != nil { | ||||
| 					if err = b.handleRateLimit(err); err != nil { | ||||
| 						b.Log.Errorf("Could not retrieve channel members: %#v", err) | ||||
| 						return | ||||
| 					} | ||||
| 					continue | ||||
| 				} | ||||
| 				newChannelMembers[channels[i].ID] = members | ||||
| 			*/ | ||||
| 		} | ||||
|  | ||||
| 		if nextCursor == "" { | ||||
| 			break | ||||
| 		} | ||||
| 		queryParams.Cursor = nextCursor | ||||
| 	} | ||||
|  | ||||
| 	b.channelsMutex.Lock() | ||||
| 	defer b.channelsMutex.Unlock() | ||||
| 	b.channelsByID = newChannelsByID | ||||
| 	b.channelsByName = newChannelsByName | ||||
|  | ||||
| 	b.channelMembersMutex.Lock() | ||||
| 	defer b.channelMembersMutex.Unlock() | ||||
| 	b.channelMembers = newChannelMembers | ||||
|  | ||||
| 	b.refreshMutex.Lock() | ||||
| 	defer b.refreshMutex.Unlock() | ||||
| 	b.earliestChannelRefresh = time.Now().Add(minimumRefreshInterval) | ||||
| 	b.refreshInProgress = false | ||||
| } | ||||
|  | ||||
| // populateReceivedMessage shapes the initial Matterbridge message that we will forward to the | ||||
| // router before we apply message-dependent modifications. | ||||
| func (b *Bslack) populateReceivedMessage(ev *slack.MessageEvent) (*config.Message, error) { | ||||
| 	// Use our own func because rtm.GetChannelInfo doesn't work for private channels. | ||||
| 	channel, err := b.getChannelByID(ev.Channel) | ||||
| 	channel, err := b.channels.getChannelByID(ev.Channel) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -289,7 +77,7 @@ func (b *Bslack) populateMessageWithUserInfo(ev *slack.MessageEvent, rmsg *confi | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	user := b.getUser(userID) | ||||
| 	user := b.users.getUser(userID) | ||||
| 	if user == nil { | ||||
| 		return fmt.Errorf("could not find information for user with id %s", ev.User) | ||||
| 	} | ||||
| @@ -315,7 +103,7 @@ func (b *Bslack) populateMessageWithBotInfo(ev *slack.MessageEvent, rmsg *config | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		if err = b.handleRateLimit(err); err != nil { | ||||
| 		if err = handleRateLimit(b.Log, err); err != nil { | ||||
| 			b.Log.Errorf("Could not retrieve bot information: %#v", err) | ||||
| 			return err | ||||
| 		} | ||||
| @@ -360,7 +148,7 @@ func (b *Bslack) extractTopicOrPurpose(text string) (string, string) { | ||||
| func (b *Bslack) replaceMention(text string) string { | ||||
| 	replaceFunc := func(match string) string { | ||||
| 		userID := strings.Trim(match, "@<>") | ||||
| 		if username := b.getUsername(userID); userID != "" { | ||||
| 		if username := b.users.getUsername(userID); userID != "" { | ||||
| 			return "@" + username | ||||
| 		} | ||||
| 		return match | ||||
| @@ -404,16 +192,6 @@ func (b *Bslack) replaceCodeFence(text string) string { | ||||
| 	return codeFenceRE.ReplaceAllString(text, "```") | ||||
| } | ||||
|  | ||||
| func (b *Bslack) handleRateLimit(err error) error { | ||||
| 	rateLimit, ok := err.(*slack.RateLimitedError) | ||||
| 	if !ok { | ||||
| 		return err | ||||
| 	} | ||||
| 	b.Log.Infof("Rate-limited by Slack. Sleeping for %v", rateLimit.RetryAfter) | ||||
| 	time.Sleep(rateLimit.RetryAfter) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // getUsersInConversation returns an array of userIDs that are members of channelID | ||||
| func (b *Bslack) getUsersInConversation(channelID string) ([]string, error) { | ||||
| 	channelMembers := []string{} | ||||
| @@ -424,7 +202,7 @@ func (b *Bslack) getUsersInConversation(channelID string) ([]string, error) { | ||||
|  | ||||
| 		members, nextCursor, err := b.sc.GetUsersInConversation(queryParams) | ||||
| 		if err != nil { | ||||
| 			if err = b.handleRateLimit(err); err != nil { | ||||
| 			if err = handleRateLimit(b.Log, err); err != nil { | ||||
| 				return channelMembers, fmt.Errorf("Could not retrieve users in channels: %#v", err) | ||||
| 			} | ||||
| 			continue | ||||
| @@ -439,3 +217,13 @@ func (b *Bslack) getUsersInConversation(channelID string) ([]string, error) { | ||||
| 	} | ||||
| 	return channelMembers, nil | ||||
| } | ||||
|  | ||||
| func handleRateLimit(log *logrus.Entry, err error) error { | ||||
| 	rateLimit, ok := err.(*slack.RateLimitedError) | ||||
| 	if !ok { | ||||
| 		return err | ||||
| 	} | ||||
| 	log.Infof("Rate-limited by Slack. Sleeping for %v", rateLimit.RetryAfter) | ||||
| 	time.Sleep(rateLimit.RetryAfter) | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -55,14 +55,18 @@ func (b *BLegacy) Connect() error { | ||||
| 		}) | ||||
| 		if b.GetString(tokenConfig) != "" { | ||||
| 			b.Log.Info("Connecting using token (receiving)") | ||||
| 			b.sc = slack.New(b.GetString(tokenConfig)) | ||||
| 			b.sc = slack.New(b.GetString(tokenConfig), slack.OptionDebug(b.GetBool("debug"))) | ||||
| 			b.channels = newChannelManager(b.Log, b.sc) | ||||
| 			b.users = newUserManager(b.Log, b.sc) | ||||
| 			b.rtm = b.sc.NewRTM() | ||||
| 			go b.rtm.ManageConnection() | ||||
| 			go b.handleSlack() | ||||
| 		} | ||||
| 	} else if b.GetString(tokenConfig) != "" { | ||||
| 		b.Log.Info("Connecting using token (sending and receiving)") | ||||
| 		b.sc = slack.New(b.GetString(tokenConfig)) | ||||
| 		b.sc = slack.New(b.GetString(tokenConfig), slack.OptionDebug(b.GetBool("debug"))) | ||||
| 		b.channels = newChannelManager(b.Log, b.sc) | ||||
| 		b.users = newUserManager(b.Log, b.sc) | ||||
| 		b.rtm = b.sc.NewRTM() | ||||
| 		go b.rtm.ManageConnection() | ||||
| 		go b.handleSlack() | ||||
|   | ||||
| @@ -30,20 +30,8 @@ type Bslack struct { | ||||
| 	uuid         string | ||||
| 	useChannelID bool | ||||
|  | ||||
| 	users      map[string]*slack.User | ||||
| 	usersMutex sync.RWMutex | ||||
|  | ||||
| 	channelsByID   map[string]*slack.Channel | ||||
| 	channelsByName map[string]*slack.Channel | ||||
| 	channelsMutex  sync.RWMutex | ||||
|  | ||||
| 	channelMembers      map[string][]string | ||||
| 	channelMembersMutex sync.RWMutex | ||||
|  | ||||
| 	refreshInProgress      bool | ||||
| 	earliestChannelRefresh time.Time | ||||
| 	earliestUserRefresh    time.Time | ||||
| 	refreshMutex           sync.Mutex | ||||
| 	channels *channels | ||||
| 	users    *users | ||||
| } | ||||
|  | ||||
| const ( | ||||
| @@ -94,14 +82,9 @@ func newBridge(cfg *bridge.Config) *Bslack { | ||||
| 		cfg.Log.Fatalf("Could not create LRU cache for Slack bridge: %v", err) | ||||
| 	} | ||||
| 	b := &Bslack{ | ||||
| 		Config:                 cfg, | ||||
| 		uuid:                   xid.New().String(), | ||||
| 		cache:                  newCache, | ||||
| 		users:                  map[string]*slack.User{}, | ||||
| 		channelsByID:           map[string]*slack.Channel{}, | ||||
| 		channelsByName:         map[string]*slack.Channel{}, | ||||
| 		earliestChannelRefresh: time.Now(), | ||||
| 		earliestUserRefresh:    time.Now(), | ||||
| 		Config: cfg, | ||||
| 		uuid:   xid.New().String(), | ||||
| 		cache:  newCache, | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
| @@ -121,7 +104,12 @@ func (b *Bslack) Connect() error { | ||||
| 	// If we have a token we use the Slack websocket-based RTM for both sending and receiving. | ||||
| 	if token := b.GetString(tokenConfig); token != "" { | ||||
| 		b.Log.Info("Connecting using token") | ||||
|  | ||||
| 		b.sc = slack.New(token, slack.OptionDebug(b.GetBool("Debug"))) | ||||
|  | ||||
| 		b.channels = newChannelManager(b.Log, b.sc) | ||||
| 		b.users = newUserManager(b.Log, b.sc) | ||||
|  | ||||
| 		b.rtm = b.sc.NewRTM() | ||||
| 		go b.rtm.ManageConnection() | ||||
| 		go b.handleSlack() | ||||
| @@ -163,9 +151,9 @@ func (b *Bslack) JoinChannel(channel config.ChannelInfo) error { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	b.populateChannels(false) | ||||
| 	b.channels.populateChannels(false) | ||||
|  | ||||
| 	channelInfo, err := b.getChannel(channel.Name) | ||||
| 	channelInfo, err := b.channels.getChannel(channel.Name) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("could not join channel: %#v", err) | ||||
| 	} | ||||
| @@ -275,7 +263,7 @@ func (b *Bslack) sendRTM(msg config.Message) (string, error) { | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	channelInfo, err := b.getChannel(msg.Channel) | ||||
| 	channelInfo, err := b.channels.getChannel(msg.Channel) | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("could not send message: %v", err) | ||||
| 	} | ||||
| @@ -351,7 +339,7 @@ func (b *Bslack) updateTopicOrPurpose(msg *config.Message, channelInfo *slack.Ch | ||||
| 		if err == nil { | ||||
| 			return nil | ||||
| 		} | ||||
| 		if err = b.handleRateLimit(err); err != nil { | ||||
| 		if err = handleRateLimit(b.Log, err); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| @@ -392,7 +380,7 @@ func (b *Bslack) deleteMessage(msg *config.Message, channelInfo *slack.Channel) | ||||
| 			return true, nil | ||||
| 		} | ||||
|  | ||||
| 		if err = b.handleRateLimit(err); err != nil { | ||||
| 		if err = handleRateLimit(b.Log, err); err != nil { | ||||
| 			b.Log.Errorf("Failed to delete user message from Slack: %#v", err) | ||||
| 			return true, err | ||||
| 		} | ||||
| @@ -411,7 +399,7 @@ func (b *Bslack) editMessage(msg *config.Message, channelInfo *slack.Channel) (b | ||||
| 			return true, nil | ||||
| 		} | ||||
|  | ||||
| 		if err = b.handleRateLimit(err); err != nil { | ||||
| 		if err = handleRateLimit(b.Log, err); err != nil { | ||||
| 			b.Log.Errorf("Failed to edit user message on Slack: %#v", err) | ||||
| 			return true, err | ||||
| 		} | ||||
| @@ -424,14 +412,18 @@ func (b *Bslack) postMessage(msg *config.Message, channelInfo *slack.Channel) (s | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	messageOptions := b.prepareMessageOptions(msg) | ||||
| 	messageOptions = append(messageOptions, slack.MsgOptionText(msg.Text, false)) | ||||
| 	messageOptions = append( | ||||
| 		messageOptions, | ||||
| 		slack.MsgOptionText(msg.Text, false), | ||||
| 		slack.MsgOptionEnableLinkUnfurl(), | ||||
| 	) | ||||
| 	for { | ||||
| 		_, id, err := b.rtm.PostMessage(channelInfo.ID, messageOptions...) | ||||
| 		if err == nil { | ||||
| 			return id, nil | ||||
| 		} | ||||
|  | ||||
| 		if err = b.handleRateLimit(err); err != nil { | ||||
| 		if err = handleRateLimit(b.Log, err); err != nil { | ||||
| 			b.Log.Errorf("Failed to sent user message to Slack: %#v", err) | ||||
| 			return "", err | ||||
| 		} | ||||
|   | ||||
							
								
								
									
										335
									
								
								bridge/slack/users_channels.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										335
									
								
								bridge/slack/users_channels.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,335 @@ | ||||
| package bslack | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/nlopes/slack" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| const minimumRefreshInterval = 10 * time.Second | ||||
|  | ||||
| type users struct { | ||||
| 	log *logrus.Entry | ||||
| 	sc  *slack.Client | ||||
|  | ||||
| 	users           map[string]*slack.User | ||||
| 	usersMutex      sync.RWMutex | ||||
| 	usersSyncPoints map[string]chan struct{} | ||||
|  | ||||
| 	refreshInProgress bool | ||||
| 	earliestRefresh   time.Time | ||||
| 	refreshMutex      sync.Mutex | ||||
| } | ||||
|  | ||||
| func newUserManager(log *logrus.Entry, sc *slack.Client) *users { | ||||
| 	return &users{ | ||||
| 		log:             log, | ||||
| 		sc:              sc, | ||||
| 		users:           make(map[string]*slack.User), | ||||
| 		usersSyncPoints: make(map[string]chan struct{}), | ||||
| 		earliestRefresh: time.Now(), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *users) getUser(id string) *slack.User { | ||||
| 	b.usersMutex.RLock() | ||||
| 	user, ok := b.users[id] | ||||
| 	b.usersMutex.RUnlock() | ||||
| 	if ok { | ||||
| 		return user | ||||
| 	} | ||||
| 	b.populateUser(id) | ||||
| 	b.usersMutex.RLock() | ||||
| 	defer b.usersMutex.RUnlock() | ||||
|  | ||||
| 	return b.users[id] | ||||
| } | ||||
|  | ||||
| func (b *users) getUsername(id string) string { | ||||
| 	if user := b.getUser(id); user != nil { | ||||
| 		if user.Profile.DisplayName != "" { | ||||
| 			return user.Profile.DisplayName | ||||
| 		} | ||||
| 		return user.Name | ||||
| 	} | ||||
| 	b.log.Warnf("Could not find user with ID '%s'", id) | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (b *users) getAvatar(id string) string { | ||||
| 	if user := b.getUser(id); user != nil { | ||||
| 		return user.Profile.Image48 | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (b *users) populateUser(userID string) { | ||||
| 	for { | ||||
| 		b.usersMutex.Lock() | ||||
| 		_, exists := b.users[userID] | ||||
| 		if exists { | ||||
| 			// already in cache | ||||
| 			b.usersMutex.Unlock() | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		if syncPoint, ok := b.usersSyncPoints[userID]; ok { | ||||
| 			// Another goroutine is already populating this user for us so wait on it to finish. | ||||
| 			b.usersMutex.Unlock() | ||||
| 			<-syncPoint | ||||
| 			// We do not return and iterate again to check that the entry does indeed exist | ||||
| 			// in case the previous query failed for some reason. | ||||
| 		} else { | ||||
| 			b.usersSyncPoints[userID] = make(chan struct{}) | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Do not hold the lock while fetching information from Slack | ||||
| 	// as this might take an unbounded amount of time. | ||||
| 	b.usersMutex.Unlock() | ||||
|  | ||||
| 	user, err := b.sc.GetUserInfo(userID) | ||||
| 	if err != nil { | ||||
| 		b.log.Debugf("GetUserInfo failed for %v: %v", userID, err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	b.usersMutex.Lock() | ||||
| 	defer b.usersMutex.Unlock() | ||||
|  | ||||
| 	// Register user information. | ||||
| 	b.users[userID] = user | ||||
|  | ||||
| 	// Wake up any waiting goroutines and remove the synchronization point. | ||||
| 	close(b.usersSyncPoints[userID]) | ||||
| 	delete(b.usersSyncPoints, userID) | ||||
| } | ||||
|  | ||||
| func (b *users) populateUsers(wait bool) { | ||||
| 	b.refreshMutex.Lock() | ||||
| 	if !wait && (time.Now().Before(b.earliestRefresh) || b.refreshInProgress) { | ||||
| 		b.log.Debugf("Not refreshing user list as it was done less than %v ago.", minimumRefreshInterval) | ||||
| 		b.refreshMutex.Unlock() | ||||
|  | ||||
| 		return | ||||
| 	} | ||||
| 	for b.refreshInProgress { | ||||
| 		b.refreshMutex.Unlock() | ||||
| 		time.Sleep(time.Second) | ||||
| 		b.refreshMutex.Lock() | ||||
| 	} | ||||
| 	b.refreshInProgress = true | ||||
| 	b.refreshMutex.Unlock() | ||||
|  | ||||
| 	newUsers := map[string]*slack.User{} | ||||
| 	pagination := b.sc.GetUsersPaginated(slack.GetUsersOptionLimit(200)) | ||||
| 	count := 0 | ||||
| 	for { | ||||
| 		var err error | ||||
| 		pagination, err = pagination.Next(context.Background()) | ||||
| 		time.Sleep(time.Second) | ||||
| 		if err != nil { | ||||
| 			if pagination.Done(err) { | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			if err = handleRateLimit(b.log, err); err != nil { | ||||
| 				b.log.Errorf("Could not retrieve users: %#v", err) | ||||
| 				return | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		for i := range pagination.Users { | ||||
| 			newUsers[pagination.Users[i].ID] = &pagination.Users[i] | ||||
| 		} | ||||
| 		b.log.Debugf("getting %d users", len(pagination.Users)) | ||||
| 		count++ | ||||
| 		// more > 2000 users, slack will complain and ratelimit. break | ||||
| 		if count > 10 { | ||||
| 			b.log.Info("Large slack detected > 2000 users, skipping loading complete userlist.") | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	b.usersMutex.Lock() | ||||
| 	defer b.usersMutex.Unlock() | ||||
| 	b.users = newUsers | ||||
|  | ||||
| 	b.refreshMutex.Lock() | ||||
| 	defer b.refreshMutex.Unlock() | ||||
| 	b.earliestRefresh = time.Now().Add(minimumRefreshInterval) | ||||
| 	b.refreshInProgress = false | ||||
| } | ||||
|  | ||||
| type channels struct { | ||||
| 	log *logrus.Entry | ||||
| 	sc  *slack.Client | ||||
|  | ||||
| 	channelsByID   map[string]*slack.Channel | ||||
| 	channelsByName map[string]*slack.Channel | ||||
| 	channelsMutex  sync.RWMutex | ||||
|  | ||||
| 	channelMembers      map[string][]string | ||||
| 	channelMembersMutex sync.RWMutex | ||||
|  | ||||
| 	refreshInProgress bool | ||||
| 	earliestRefresh   time.Time | ||||
| 	refreshMutex      sync.Mutex | ||||
| } | ||||
|  | ||||
| func newChannelManager(log *logrus.Entry, sc *slack.Client) *channels { | ||||
| 	return &channels{ | ||||
| 		log:             log, | ||||
| 		sc:              sc, | ||||
| 		channelsByID:    make(map[string]*slack.Channel), | ||||
| 		channelsByName:  make(map[string]*slack.Channel), | ||||
| 		earliestRefresh: time.Now(), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *channels) getChannel(channel string) (*slack.Channel, error) { | ||||
| 	if strings.HasPrefix(channel, "ID:") { | ||||
| 		return b.getChannelByID(strings.TrimPrefix(channel, "ID:")) | ||||
| 	} | ||||
| 	return b.getChannelByName(channel) | ||||
| } | ||||
|  | ||||
| func (b *channels) getChannelByName(name string) (*slack.Channel, error) { | ||||
| 	return b.getChannelBy(name, b.channelsByName) | ||||
| } | ||||
|  | ||||
| func (b *channels) getChannelByID(id string) (*slack.Channel, error) { | ||||
| 	return b.getChannelBy(id, b.channelsByID) | ||||
| } | ||||
|  | ||||
| func (b *channels) getChannelBy(lookupKey string, lookupMap map[string]*slack.Channel) (*slack.Channel, error) { | ||||
| 	b.channelsMutex.RLock() | ||||
| 	defer b.channelsMutex.RUnlock() | ||||
|  | ||||
| 	if channel, ok := lookupMap[lookupKey]; ok { | ||||
| 		return channel, nil | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("channel %s not found", lookupKey) | ||||
| } | ||||
|  | ||||
| func (b *channels) getChannelMembers(users *users) config.ChannelMembers { | ||||
| 	b.channelMembersMutex.RLock() | ||||
| 	defer b.channelMembersMutex.RUnlock() | ||||
|  | ||||
| 	membersInfo := config.ChannelMembers{} | ||||
| 	for channelID, members := range b.channelMembers { | ||||
| 		for _, member := range members { | ||||
| 			channelName := "" | ||||
| 			userName := "" | ||||
| 			userNick := "" | ||||
| 			user := users.getUser(member) | ||||
| 			if user != nil { | ||||
| 				userName = user.Name | ||||
| 				userNick = user.Profile.DisplayName | ||||
| 			} | ||||
| 			channel, _ := b.getChannelByID(channelID) | ||||
| 			if channel != nil { | ||||
| 				channelName = channel.Name | ||||
| 			} | ||||
| 			memberInfo := config.ChannelMember{ | ||||
| 				Username:    userName, | ||||
| 				Nick:        userNick, | ||||
| 				UserID:      member, | ||||
| 				ChannelID:   channelID, | ||||
| 				ChannelName: channelName, | ||||
| 			} | ||||
| 			membersInfo = append(membersInfo, memberInfo) | ||||
| 		} | ||||
| 	} | ||||
| 	return membersInfo | ||||
| } | ||||
|  | ||||
| func (b *channels) registerChannel(channel slack.Channel) { | ||||
| 	b.channelsMutex.Lock() | ||||
| 	defer b.channelsMutex.Unlock() | ||||
|  | ||||
| 	b.channelsByID[channel.ID] = &channel | ||||
| 	b.channelsByName[channel.Name] = &channel | ||||
| } | ||||
|  | ||||
| func (b *channels) populateChannels(wait bool) { | ||||
| 	b.refreshMutex.Lock() | ||||
| 	if !wait && (time.Now().Before(b.earliestRefresh) || b.refreshInProgress) { | ||||
| 		b.log.Debugf("Not refreshing channel list as it was done less than %v seconds ago.", minimumRefreshInterval) | ||||
| 		b.refreshMutex.Unlock() | ||||
| 		return | ||||
| 	} | ||||
| 	for b.refreshInProgress { | ||||
| 		b.refreshMutex.Unlock() | ||||
| 		time.Sleep(time.Second) | ||||
| 		b.refreshMutex.Lock() | ||||
| 	} | ||||
| 	b.refreshInProgress = true | ||||
| 	b.refreshMutex.Unlock() | ||||
|  | ||||
| 	newChannelsByID := map[string]*slack.Channel{} | ||||
| 	newChannelsByName := map[string]*slack.Channel{} | ||||
| 	newChannelMembers := make(map[string][]string) | ||||
|  | ||||
| 	// We only retrieve public and private channels, not IMs | ||||
| 	// and MPIMs as those do not have a channel name. | ||||
| 	queryParams := &slack.GetConversationsParameters{ | ||||
| 		ExcludeArchived: "true", | ||||
| 		Types:           []string{"public_channel,private_channel"}, | ||||
| 	} | ||||
| 	for { | ||||
| 		channels, nextCursor, err := b.sc.GetConversations(queryParams) | ||||
| 		if err != nil { | ||||
| 			if err = handleRateLimit(b.log, err); err != nil { | ||||
| 				b.log.Errorf("Could not retrieve channels: %#v", err) | ||||
| 				return | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		for i := range channels { | ||||
| 			newChannelsByID[channels[i].ID] = &channels[i] | ||||
| 			newChannelsByName[channels[i].Name] = &channels[i] | ||||
| 			// also find all the members in every channel | ||||
| 			// comment for now, issues on big slacks | ||||
| 			/* | ||||
| 				members, err := b.getUsersInConversation(channels[i].ID) | ||||
| 				if err != nil { | ||||
| 					if err = b.handleRateLimit(err); err != nil { | ||||
| 						b.Log.Errorf("Could not retrieve channel members: %#v", err) | ||||
| 						return | ||||
| 					} | ||||
| 					continue | ||||
| 				} | ||||
| 				newChannelMembers[channels[i].ID] = members | ||||
| 			*/ | ||||
| 		} | ||||
|  | ||||
| 		if nextCursor == "" { | ||||
| 			break | ||||
| 		} | ||||
| 		queryParams.Cursor = nextCursor | ||||
| 	} | ||||
|  | ||||
| 	b.channelsMutex.Lock() | ||||
| 	defer b.channelsMutex.Unlock() | ||||
| 	b.channelsByID = newChannelsByID | ||||
| 	b.channelsByName = newChannelsByName | ||||
|  | ||||
| 	b.channelMembersMutex.Lock() | ||||
| 	defer b.channelMembersMutex.Unlock() | ||||
| 	b.channelMembers = newChannelMembers | ||||
|  | ||||
| 	b.refreshMutex.Lock() | ||||
| 	defer b.refreshMutex.Unlock() | ||||
| 	b.earliestRefresh = time.Now().Add(minimumRefreshInterval) | ||||
| 	b.refreshInProgress = false | ||||
| } | ||||
| @@ -144,6 +144,9 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | ||||
| 		// quote the previous message | ||||
| 		b.handleQuoting(&rmsg, message) | ||||
|  | ||||
| 		// handle entities (adding URLs) | ||||
| 		b.handleEntities(&rmsg, message) | ||||
|  | ||||
| 		if rmsg.Text != "" || len(rmsg.Extra) > 0 { | ||||
| 			rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text) | ||||
| 			// channels don't have (always?) user information. see #410 | ||||
| @@ -245,6 +248,15 @@ func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Messa | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if strings.HasSuffix(name, ".webp") && b.GetBool("MediaConvertWebPToPNG") { | ||||
| 		b.Log.Debugf("WebP to PNG conversion enabled, converting %s", name) | ||||
| 		err := helper.ConvertWebPToPNG(data) | ||||
| 		if err != nil { | ||||
| 			b.Log.Errorf("conversion failed: %s", err) | ||||
| 		} else { | ||||
| 			name = strings.Replace(name, ".webp", ".png", 1) | ||||
| 		} | ||||
| 	} | ||||
| 	helper.HandleDownloadData(b.Log, rmsg, name, message.Caption, "", data, b.General) | ||||
| 	return nil | ||||
| } | ||||
| @@ -344,3 +356,22 @@ func (b *Btelegram) handleQuote(message, quoteNick, quoteMessage string) string | ||||
| 	format = strings.Replace(format, "{QUOTEMESSAGE}", quoteMessage, -1) | ||||
| 	return format | ||||
| } | ||||
|  | ||||
| // handleEntities handles messageEntities | ||||
| func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Message) { | ||||
| 	if message.Entities == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	// for now only do URL replacements | ||||
| 	for _, e := range *message.Entities { | ||||
| 		if e.Type == "text_link" { | ||||
| 			url, err := e.ParseURL() | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("entity text_link url parse failed: %s", err) | ||||
| 				continue | ||||
| 			} | ||||
| 			link := rmsg.Text[e.Offset : e.Offset+e.Length] | ||||
| 			rmsg.Text = strings.Replace(rmsg.Text, link, url.String(), 1) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -3,7 +3,6 @@ package btelegram | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"html" | ||||
| 	"io" | ||||
|  | ||||
| 	"github.com/russross/blackfriday" | ||||
| ) | ||||
| @@ -33,7 +32,7 @@ func (options *customHTML) Header(out *bytes.Buffer, text func() bool, level int | ||||
| 	options.Paragraph(out, text) | ||||
| } | ||||
|  | ||||
| func (options *customHTML) HRule(out io.ByteWriter) { | ||||
| func (options *customHTML) HRule(out *bytes.Buffer) { | ||||
| 	out.WriteByte('\n') //nolint:errcheck | ||||
| } | ||||
|  | ||||
| @@ -54,16 +53,13 @@ func (options *customHTML) ListItem(out *bytes.Buffer, text []byte, flags int) { | ||||
| } | ||||
|  | ||||
| func makeHTML(input string) string { | ||||
| 	extensions := blackfriday.NoIntraEmphasis | | ||||
| 		blackfriday.FencedCode | | ||||
| 		blackfriday.Autolink | | ||||
| 		blackfriday.SpaceHeadings | | ||||
| 		blackfriday.HeadingIDs | | ||||
| 		blackfriday.BackslashLineBreak | | ||||
| 		blackfriday.DefinitionLists | ||||
|  | ||||
| 	renderer := &customHTML{blackfriday.NewHTMLRenderer(blackfriday.HTMLRendererParameters{ | ||||
| 		Flags: blackfriday.UseXHTML | blackfriday.SkipImages, | ||||
| 	})} | ||||
| 	return string(blackfriday.Run([]byte(input), blackfriday.WithExtensions(extensions), blackfriday.WithRenderer(renderer))) | ||||
| 	return string(blackfriday.Markdown([]byte(input), | ||||
| 		&customHTML{blackfriday.HtmlRenderer(blackfriday.HTML_USE_XHTML|blackfriday.HTML_SKIP_IMAGES, "", "")}, | ||||
| 		blackfriday.EXTENSION_NO_INTRA_EMPHASIS| | ||||
| 			blackfriday.EXTENSION_FENCED_CODE| | ||||
| 			blackfriday.EXTENSION_AUTOLINK| | ||||
| 			blackfriday.EXTENSION_SPACE_HEADERS| | ||||
| 			blackfriday.EXTENSION_HEADER_IDS| | ||||
| 			blackfriday.EXTENSION_BACKSLASH_LINE_BREAK| | ||||
| 			blackfriday.EXTENSION_DEFINITION_LISTS)) | ||||
| } | ||||
|   | ||||
| @@ -6,9 +6,9 @@ import ( | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
|  | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/matterbridge/go-whatsapp" | ||||
|  | ||||
| 	whatsappExt "maunium.net/go/mautrix-whatsapp/whatsapp-ext" | ||||
| 	whatsappExt "github.com/matterbridge/mautrix-whatsapp/whatsapp-ext" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|   | ||||
| @@ -6,7 +6,7 @@ import ( | ||||
| 	"os" | ||||
|  | ||||
| 	qrcodeTerminal "github.com/Baozisoftware/qrcode-terminal-go" | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/matterbridge/go-whatsapp" | ||||
| ) | ||||
|  | ||||
| func qrFromTerminal(invert bool) chan string { | ||||
|   | ||||
| @@ -12,9 +12,9 @@ import ( | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
|  | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/matterbridge/go-whatsapp" | ||||
|  | ||||
| 	whatsappExt "maunium.net/go/mautrix-whatsapp/whatsapp-ext" | ||||
| 	whatsappExt "github.com/matterbridge/mautrix-whatsapp/whatsapp-ext" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import ( | ||||
| 	"encoding/json" | ||||
| 	"io/ioutil" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| @@ -18,12 +19,11 @@ type Bzulip struct { | ||||
| 	bot     *gzb.Bot | ||||
| 	streams map[int]string | ||||
| 	*bridge.Config | ||||
| 	channelToTopic map[string]string | ||||
| 	sync.RWMutex | ||||
| } | ||||
|  | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	return &Bzulip{Config: cfg, streams: make(map[int]string), channelToTopic: make(map[string]string)} | ||||
| 	return &Bzulip{Config: cfg, streams: make(map[int]string)} | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) Connect() error { | ||||
| @@ -48,9 +48,6 @@ func (b *Bzulip) Disconnect() error { | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	b.Lock() | ||||
| 	defer b.Unlock() | ||||
| 	b.channelToTopic[channel.Name] = channel.Options.Topic | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -116,11 +113,13 @@ func (b *Bzulip) handleQueue() error { | ||||
| 		case gzb.BadEventQueueError: | ||||
| 			b.Log.Info("got a bad event queue id error, reconnecting") | ||||
| 			b.bot.Queues = nil | ||||
| 			b.q, err = b.bot.RegisterAll() | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("reconnecting failed: %s. Sleeping 10 seconds", err) | ||||
| 				time.Sleep(time.Second * 10) | ||||
| 				continue | ||||
| 			for { | ||||
| 				b.q, err = b.bot.RegisterAll() | ||||
| 				if err != nil { | ||||
| 					b.Log.Errorf("reconnecting failed: %s. Sleeping 10 seconds", err) | ||||
| 					time.Sleep(time.Second * 10) | ||||
| 				} | ||||
| 				break | ||||
| 			} | ||||
| 		case gzb.HeartbeatError: | ||||
| 			b.Log.Debug("heartbeat received.") | ||||
| @@ -136,7 +135,14 @@ func (b *Bzulip) handleQueue() error { | ||||
| 			if m.SenderEmail == b.GetString("login") { | ||||
| 				continue | ||||
| 			} | ||||
| 			rmsg := config.Message{Username: m.SenderFullName, Text: m.Content, Channel: b.getChannel(m.StreamID), Account: b.Account, UserID: strconv.Itoa(m.SenderID), Avatar: m.AvatarURL} | ||||
| 			rmsg := config.Message{ | ||||
| 				Username: m.SenderFullName, | ||||
| 				Text:     m.Content, | ||||
| 				Channel:  b.getChannel(m.StreamID) + "/topic:" + m.Subject, | ||||
| 				Account:  b.Account, | ||||
| 				UserID:   strconv.Itoa(m.SenderID), | ||||
| 				Avatar:   m.AvatarURL, | ||||
| 			} | ||||
| 			b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account) | ||||
| 			b.Log.Debugf("<= Message is %#v", rmsg) | ||||
| 			b.Remote <- rmsg | ||||
| @@ -147,12 +153,11 @@ func (b *Bzulip) handleQueue() error { | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) sendMessage(msg config.Message) (string, error) { | ||||
| 	topic := "matterbridge" | ||||
| 	if b.GetString("topic") != "" { | ||||
| 		topic = b.GetString("topic") | ||||
| 	} | ||||
| 	if res := b.getTopic(msg.Channel); res != "" { | ||||
| 		topic = res | ||||
| 	topic := "" | ||||
| 	if strings.Contains(msg.Channel, "/topic:") { | ||||
| 		res := strings.Split(msg.Channel, "/topic:") | ||||
| 		topic = res[1] | ||||
| 		msg.Channel = res[0] | ||||
| 	} | ||||
| 	m := gzb.Message{ | ||||
| 		Stream:  msg.Channel, | ||||
| @@ -200,9 +205,3 @@ func (b *Bzulip) handleUploadFile(msg *config.Message) (string, error) { | ||||
| 	} | ||||
| 	return "", nil | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) getTopic(channel string) string { | ||||
| 	b.RLock() | ||||
| 	defer b.RUnlock() | ||||
| 	return b.channelToTopic[channel] | ||||
| } | ||||
|   | ||||
							
								
								
									
										26
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,4 +1,11 @@ | ||||
| # v1.14.0-rc1 | ||||
| # v1.14.1 | ||||
| ## Bugfix | ||||
| * slack: Fix crash double unlock (slack) (#771) | ||||
|  | ||||
| # v1.14.0 | ||||
|  | ||||
| ## Breaking | ||||
| * zulip: Need to specify /topic:mytopic for channel configuration (zulip). (#751) | ||||
|  | ||||
| ## New features | ||||
| * whatsapp: new protocol added. Add initial WhatsApp support (#711) Thanks to @KrzysztofMadejski | ||||
| @@ -10,18 +17,29 @@ | ||||
| * rocketchat: add support for the rocketchat API. Sending to rocketchat now supports uploading of files, editing and deleting of messages. | ||||
| * discord: Support join/leaves from discord. Closes #654 (#721) | ||||
| * discord: Allow sending discriminator with Discord username (#726). See `UseDiscriminator` in matterbridge.toml.sample | ||||
| * zulip: Allow zulip bridge to specify topic per channel. Closes #701 (#723). See `Topic` in matterbridge.toml.sample | ||||
| * slack: Add extra debug option (slack). See `Debug` in the slack section in matterbridge.toml.sample | ||||
| * telegram: Add support for URL in messageEntities (telegram). Fixes #735 (#736) | ||||
| * telegram: Add MediaConvertWebPToPNG option (telegram). (#741). See `MediaConvertWebPToPNG` in matterbridge.toml.sample | ||||
|  | ||||
| ## Enhancements | ||||
| * general: Fail gracefully on incorrect human input. Fixes #739 (#740) | ||||
| * matrix: Detect html nicks in RemoteNickFormat (matrix). Fixes #696 (#719) | ||||
| * matrix: Send notices on join/parts (matrix). Fixes #712 (#716) | ||||
|  | ||||
| ## Bugfix | ||||
| * general: Handle file upload/download only once for each message (#742) | ||||
| * zulip: Fix error handling on bad event queue id (zulip). Closes #694 | ||||
| * zulip: Keep reconnecting until succeed (zulip) (#737) | ||||
| * irc: add support for (older) unrealircd versions. #708 | ||||
| * irc: Support quits from irc correctly. Fixes #722 (#724) | ||||
| * matrix: Send username when uploading video/images (matrix). Fixes #715 (#717) | ||||
| * matrix: Send notices on join/parts (matrix). Fixes #712 (#716) | ||||
| * matrix: Detect html nicks in RemoteNickFormat (matrix). Fixes #696 (#719) | ||||
| * matrix: Trim <p> and </p> tags (matrix). Closes #686 (#753) | ||||
| * slack: Hint at thread replies when messages are unthreaded (slack) (#684) | ||||
| * slack: Fix race-condition in populateUser() (#767) | ||||
| * xmpp: Do not send topic changes on connect (xmpp). Fixes #732 (#733) | ||||
| * telegram: Fix regression in HTML handling (telegram). Closes #734 | ||||
| * discord: Do not relay any bot messages (discord) (#743) | ||||
| * rocketchat: Do not send duplicate messages (rocketchat). Fixes #745 (#752) | ||||
|  | ||||
| ## Contributors | ||||
| This release couldn't exist without the following contributors: | ||||
|   | ||||
| @@ -92,6 +92,9 @@ func (gw *Gateway) AddBridge(cfg *config.Bridge) error { | ||||
| 			Bridge: br, | ||||
| 		} | ||||
| 		// add the actual bridger for this protocol to this bridge using the bridgeMap | ||||
| 		if _, ok := gw.Router.BridgeMap[br.Protocol]; !ok { | ||||
| 			gw.logger.Fatalf("Incorrect protocol %s specified in gateway configuration %s, exiting.", br.Protocol, cfg.Account) | ||||
| 		} | ||||
| 		br.Bridger = gw.Router.BridgeMap[br.Protocol](brconfig) | ||||
| 	} | ||||
| 	gw.mapChannelsToBridge(br) | ||||
| @@ -156,6 +159,10 @@ func (gw *Gateway) mapChannelConfig(cfg []config.Bridge, direction string) { | ||||
| 			gw.logger.Errorf("Mattermost channels do not start with a #: remove the # in %s", br.Channel) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		if strings.HasPrefix(br.Account, "zulip.") && !strings.Contains(br.Channel, "/topic:") { | ||||
| 			gw.logger.Errorf("Breaking change, since matterbridge 1.14.0 zulip channels need to specify the topic with channel/topic:mytopic in %s of %s", br.Channel, br.Account) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 		ID := br.Channel + br.Account | ||||
| 		if _, ok := gw.Channels[ID]; !ok { | ||||
| 			channel := &config.ChannelInfo{ | ||||
|   | ||||
| @@ -125,6 +125,7 @@ func (r *Router) handleReceive() { | ||||
| 		r.handleEventGetChannelMembers(&msg) | ||||
| 		r.handleEventFailure(&msg) | ||||
| 		r.handleEventRejoinChannels(&msg) | ||||
| 		idx := 0 | ||||
| 		for _, gw := range r.Gateways { | ||||
| 			// record all the message ID's of the different bridges | ||||
| 			var msgIDs []*BrMsgID | ||||
| @@ -133,7 +134,9 @@ func (r *Router) handleReceive() { | ||||
| 			} | ||||
| 			msg.Timestamp = time.Now() | ||||
| 			gw.modifyMessage(&msg) | ||||
| 			gw.handleFiles(&msg) | ||||
| 			if idx == 0 { | ||||
| 				gw.handleFiles(&msg) | ||||
| 			} | ||||
| 			for _, br := range gw.Bridges { | ||||
| 				msgIDs = append(msgIDs, gw.handleMessage(&msg, br)...) | ||||
| 			} | ||||
| @@ -141,6 +144,7 @@ func (r *Router) handleReceive() { | ||||
| 			if _, ok := gw.Messages.Get(msg.Protocol + " " + msg.ID); !ok && msg.ID != "" { | ||||
| 				gw.Messages.Add(msg.Protocol+" "+msg.ID, msgIDs) | ||||
| 			} | ||||
| 			idx++ | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										9
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								go.mod
									
									
									
									
									
								
							| @@ -6,9 +6,8 @@ require ( | ||||
| 	github.com/BurntSushi/toml v0.0.0-20170318202913-d94612f9fc14 // indirect | ||||
| 	github.com/Jeffail/gabs v1.1.1 // indirect | ||||
| 	github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329 | ||||
| 	github.com/Rhymen/go-whatsapp v0.0.0-20190208184307-c9a81e957884 | ||||
| 	github.com/bwmarrin/discordgo v0.19.0 | ||||
| 	github.com/d5/tengo v1.9.2 | ||||
| 	github.com/d5/tengo v1.12.1 | ||||
| 	github.com/dfordsoft/golib v0.0.0-20180902042739-76ee6ab99bec | ||||
| 	github.com/fsnotify/fsnotify v1.4.7 | ||||
| 	github.com/go-telegram-bot-api/telegram-bot-api v4.6.5-0.20181225215658-ec221ba9ea45+incompatible | ||||
| @@ -28,10 +27,12 @@ require ( | ||||
| 	github.com/lusis/go-slackbot v0.0.0-20180109053408-401027ccfef5 // indirect | ||||
| 	github.com/lusis/slack-test v0.0.0-20180109053238-3c758769bfa6 // indirect | ||||
| 	github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d | ||||
| 	github.com/matterbridge/go-whatsapp v0.0.1-0.20190301204034-f2f1b29d441b | ||||
| 	github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 | ||||
| 	github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea | ||||
| 	github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18 | ||||
| 	github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61 | ||||
| 	github.com/matterbridge/mautrix-whatsapp v0.0.0-20190301210046-3539cf52ed6e | ||||
| 	github.com/mattermost/mattermost-server v5.5.0+incompatible | ||||
| 	github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect | ||||
| 	github.com/mreiferson/go-httpclient v0.0.0-20160630210159-31f0106b4474 // indirect | ||||
| @@ -46,7 +47,7 @@ require ( | ||||
| 	github.com/peterhellberg/emojilib v0.0.0-20190124112554-c18758d55320 | ||||
| 	github.com/pkg/errors v0.8.0 // indirect | ||||
| 	github.com/rs/xid v1.2.1 | ||||
| 	github.com/russross/blackfriday v2.0.0+incompatible | ||||
| 	github.com/russross/blackfriday v1.5.2 | ||||
| 	github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca | ||||
| 	github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296 | ||||
| 	github.com/sirupsen/logrus v1.3.0 | ||||
| @@ -66,8 +67,8 @@ require ( | ||||
| 	go.uber.org/atomic v1.3.2 // indirect | ||||
| 	go.uber.org/multierr v1.1.0 // indirect | ||||
| 	go.uber.org/zap v1.9.1 // indirect | ||||
| 	golang.org/x/image v0.0.0-20190220214146-31aff87c08e9 | ||||
| 	gopkg.in/fsnotify.v1 v1.4.7 // indirect | ||||
| 	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect | ||||
| 	gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect | ||||
| 	maunium.net/go/mautrix-whatsapp v0.0.0-20190127121751-281b3e8f77f3 | ||||
| ) | ||||
|   | ||||
							
								
								
									
										45
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										45
									
								
								go.sum
									
									
									
									
									
								
							| @@ -8,11 +8,6 @@ github.com/Jeffail/gabs v1.1.1 h1:V0uzR08Hj22EX8+8QMhyI9sX2hwRu+/RJhJUmnwda/E= | ||||
| github.com/Jeffail/gabs v1.1.1/go.mod h1:6xMvQMK4k33lb7GUUpaAPh6nKMmemQeg5d4gn7/bOXc= | ||||
| github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329 h1:xZBoq249G9MSt+XuY7sVQzcfONJ6IQuwpCK+KAaOpnY= | ||||
| github.com/Philipp15b/go-steam v1.0.1-0.20180818081528-681bd9573329/go.mod h1:HuVM+sZFzumUdKPWiz+IlCMb4RdsKdT3T+nQBKL+sYg= | ||||
| github.com/Rhymen/go-whatsapp v0.0.0-20181218094654-2ca6af00572c h1:ldRXgMEfKmzBomrZusl3edG9AGEeztA7jovLEQy62us= | ||||
| github.com/Rhymen/go-whatsapp v0.0.0-20181218094654-2ca6af00572c/go.mod h1:MSDmePOOkbFFbVW2WRRppBcbA+aabwpXRgyIIG7jDFQ= | ||||
| github.com/Rhymen/go-whatsapp v0.0.0-20190208184307-c9a81e957884 h1:2AxfzkQi2L4QGBvUCZoWD6hQuUJa5MG54wiYyNqJlf4= | ||||
| github.com/Rhymen/go-whatsapp v0.0.0-20190208184307-c9a81e957884/go.mod h1:rdQr95g2C1xcOfM7QGOhza58HeI3I+tZ/bbluv7VazA= | ||||
| github.com/alexcesaro/log v0.0.0-20150915221235-61e686294e58 h1:MkpmYfld/S8kXqTYI68DfL8/hHXjHogL120Dy00TIxc= | ||||
| github.com/alexcesaro/log v0.0.0-20150915221235-61e686294e58/go.mod h1:YNfsMyWSs+h+PaYkxGeMVmVCX75Zj/pqdjbu12ciCYE= | ||||
| github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= | ||||
| github.com/bwmarrin/discordgo v0.19.0 h1:kMED/DB0NR1QhRcalb85w0Cu3Ep2OrGAqZH1R5awQiY= | ||||
| @@ -20,8 +15,8 @@ github.com/bwmarrin/discordgo v0.19.0/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVO | ||||
| github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= | ||||
| github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= | ||||
| github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= | ||||
| github.com/d5/tengo v1.9.2 h1:UE/X8PYl7bLS4Ww2zGeh91nq5PTnkhe8ncgNeA5PK7k= | ||||
| github.com/d5/tengo v1.9.2/go.mod h1:gsbjo7lBXzBIWBd6NQp1lRKqqiDDANqBOyhW8rTlFsY= | ||||
| github.com/d5/tengo v1.12.1 h1:libKkDM95CsZgYs6E5eiEaM9sbcw2EzJRSkr9o5NO4s= | ||||
| github.com/d5/tengo v1.12.1/go.mod h1:gsbjo7lBXzBIWBd6NQp1lRKqqiDDANqBOyhW8rTlFsY= | ||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||
| @@ -43,6 +38,7 @@ github.com/gopackage/ddp v0.0.0-20170117053602-652027933df4/go.mod h1:lEO7XoHJ/x | ||||
| github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f h1:FDM3EtwZLyhW48YRiyqjivNlNZjAObv4xt4NnJaU+NQ= | ||||
| github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | ||||
| github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= | ||||
| github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= | ||||
| github.com/gorilla/schema v1.0.2 h1:sAgNfOcNYvdDSrzGHVy9nzCQahG+qmsg+nE8dK85QRA= | ||||
| github.com/gorilla/schema v1.0.2/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= | ||||
| github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= | ||||
| @@ -82,6 +78,8 @@ github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDe | ||||
| github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= | ||||
| github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d h1:F+Sr+C0ojSlYQ37BLylQtSFmyQULe3jbAygcyXQ9mVs= | ||||
| github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20190210153444-cc9d05784d5d/go.mod h1:c6MxwqHD+0HvtAJjsHMIdPCiAwGiQwPRPTp69ACMg8A= | ||||
| github.com/matterbridge/go-whatsapp v0.0.1-0.20190301204034-f2f1b29d441b h1:cO6Z+yj4Ivq/ay/IxSrV90oSIW/SSXWLa+XHsiLKMrw= | ||||
| github.com/matterbridge/go-whatsapp v0.0.1-0.20190301204034-f2f1b29d441b/go.mod h1:dW19fYkkdUZsBAx7zv9fDh0n6NRqYIaKwB2JEBw8d0U= | ||||
| github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91 h1:KzDEcy8eDbTx881giW8a6llsAck3e2bJvMyKvh1IK+k= | ||||
| github.com/matterbridge/go-xmpp v0.0.0-20180529212104-cd19799fba91/go.mod h1:ECDRehsR9TYTKCAsRS8/wLeOk6UUqDydw47ln7wG41Q= | ||||
| github.com/matterbridge/gomatrix v0.0.0-20190102230110-6f9631ca6dea h1:kaADGqpK4gGO2BpzEyJrBxq2Jc57Rsar4i2EUxcACUc= | ||||
| @@ -90,12 +88,16 @@ github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18 h1:fLhwXtW | ||||
| github.com/matterbridge/gozulipbot v0.0.0-20190212232658-7aa251978a18/go.mod h1:yAjnZ34DuDyPHMPHHjOsTk/FefW4JJjoMMCGt/8uuQA= | ||||
| github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61 h1:R/MgM/eUyRBQx2FiH6JVmXck8PaAuKfe2M1tWIzW7nE= | ||||
| github.com/matterbridge/logrus-prefixed-formatter v0.0.0-20180806162718-01618749af61/go.mod h1:iXGEotOvwI1R1SjLxRc+BF5rUORTMtE0iMZBT2lxqAU= | ||||
| github.com/matterbridge/mautrix-whatsapp v0.0.0-20190301210046-3539cf52ed6e h1:1NqciL8sz+0UYeFrd/UQlL8tJPhFxOBmg+a94DN2sJU= | ||||
| github.com/matterbridge/mautrix-whatsapp v0.0.0-20190301210046-3539cf52ed6e/go.mod h1:DrIFGcFumRlEW5k3PJjWGKPd4+w37d3SwOxlh1ZAL+4= | ||||
| github.com/mattermost/mattermost-server v5.5.0+incompatible h1:0wcLGgYtd+YImtLDPf2AOfpBHxbU4suATx+6XKw1XbU= | ||||
| github.com/mattermost/mattermost-server v5.5.0+incompatible/go.mod h1:5L6MjAec+XXQwMIt791Ganu45GKsSiM+I0tLR9wUj8Y= | ||||
| github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= | ||||
| github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= | ||||
| github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= | ||||
| github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg= | ||||
| github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= | ||||
| github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= | ||||
| github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= | ||||
| github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= | ||||
| github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | ||||
| github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= | ||||
| github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= | ||||
| @@ -129,8 +131,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb | ||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||
| github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= | ||||
| github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= | ||||
| github.com/russross/blackfriday v2.0.0+incompatible h1:cBXrhZNUf9C+La9/YpS+UHpUT8YD6Td9ZMSU9APFcsk= | ||||
| github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= | ||||
| github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= | ||||
| github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= | ||||
| github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= | ||||
| github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxTvN8n+Kvkn6TrbMyxQiuvKdEwFdR9vI= | ||||
| github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU= | ||||
| @@ -138,11 +140,9 @@ github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1 h1:Lx3BlDGFElJt4u/zK | ||||
| github.com/shazow/rateio v0.0.0-20150116013248-e8e00881e5c1/go.mod h1:vt2jWY/3Qw1bIzle5thrJWucsLuuX9iUNnp20CqCciI= | ||||
| github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296 h1:8RLq547MSVc6vhOuCl4Ca0TsAQknj6NX6ZLSZ3+xmio= | ||||
| github.com/shazow/ssh-chat v0.0.0-20190125184227-81d7e1686296/go.mod h1:1GLXsL4esywkpNId3v4QWuMf3THtWGitWvtQ/L3aSA4= | ||||
| github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= | ||||
| github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= | ||||
| github.com/sirupsen/logrus v1.3.0 h1:hI/7Q+DtNZ2kINb6qt/lS+IyXnHQe9e90POfeewL/ME= | ||||
| github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= | ||||
| github.com/skip2/go-qrcode v0.0.0-20171229120447-cf5f9fa2f0d8/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo= | ||||
| github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9 h1:lpEzuenPuO1XNTeikEmvqYFcU37GVLl8SRNblzyvGBE= | ||||
| github.com/skip2/go-qrcode v0.0.0-20190110000554-dc11ecdae0a9/go.mod h1:PLPIyL7ikehBD1OAjmKKiOEhbvWyHGaNDjquXMcYABo= | ||||
| github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9 h1:lXQ+j+KwZcbwrbgU0Rp4Eglg3EJLHbuZU3BbOqAGBmg= | ||||
| @@ -160,9 +160,7 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn | ||||
| github.com/spf13/viper v1.3.1 h1:5+8j8FTpnFV4nEImW/ofkzEt8VoOiLXxdYIDsB73T38= | ||||
| github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= | ||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= | ||||
| github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||||
| github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= | ||||
| github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= | ||||
| github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | ||||
| github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||||
| @@ -197,25 +195,24 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ | ||||
| go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= | ||||
| go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= | ||||
| golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16 h1:y6ce7gCWtnH+m3dCjzQ1PCuwl28DDIc3VNnvY29DlIA= | ||||
| golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664 h1:YbZJ76lQ1BqNhVe7dKTSB67wDrc2VPRR75IyGyyPDX8= | ||||
| golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613 h1:MQ/ZZiDsUapFFiMS+vzwXkCTeEKaum+Do5rINYJDmxc= | ||||
| golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f h1:qWFY9ZxP3tfI37wYIs/MnIAqK0vlXp1xnYEa5HxFSSY= | ||||
| golang.org/x/crypto v0.0.0-20190222235706-ffb98f73852f/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/image v0.0.0-20190220214146-31aff87c08e9 h1:+vH8qNweCrORN49012OX3h0oWEXO3p+rRnpAGQinddk= | ||||
| golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= | ||||
| golang.org/x/net v0.0.0-20190110200230-915654e7eabc h1:Yx9JGxI1SBhVLFjpAkWMaO1TF+xyqtHLjZpvQboJGiM= | ||||
| golang.org/x/net v0.0.0-20190110200230-915654e7eabc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= | ||||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20181212120007-b05ddf57801d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190109145017-48ac38b7c8cb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc h1:WiYx1rIFmx8c0mXAFtv5D/mHyKe1+jmuP7PViuwqwuQ= | ||||
| golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190222171317-cd391775e71e h1:oF7qaQxUH6KzFdKN4ww7NpPdo53SZi4UlcksLrb2y/o= | ||||
| golang.org/x/sys v0.0.0-20190222171317-cd391775e71e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= | ||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||
| @@ -233,5 +230,3 @@ maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfk | ||||
| maunium.net/go/maulogger/v2 v2.0.0/go.mod h1:Hbbkq3NV6jvJodByZu1mgEF3fpT7Kz9z0MjEZ3/BusI= | ||||
| maunium.net/go/mautrix v0.1.0-alpha.3/go.mod h1:GTVu6WDHR+98DKOrYetWsXorvUeKQV3jsSWO6ScbuFI= | ||||
| maunium.net/go/mautrix-appservice v0.1.0-alpha.3/go.mod h1:wOnWOIuprYad7ly12rHIo3JLCPh4jwvx1prVrAB9RhM= | ||||
| maunium.net/go/mautrix-whatsapp v0.0.0-20190127121751-281b3e8f77f3 h1:A18t5Lp7I3aK0V7B7zdpb0hb/PBlu0X/Ai2AyU/XEk4= | ||||
| maunium.net/go/mautrix-whatsapp v0.0.0-20190127121751-281b3e8f77f3/go.mod h1:r5E3J4urDEsjfui9OYZYMLBfCliaAqcCwM2xeczta6k= | ||||
|   | ||||
| @@ -15,7 +15,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	version = "1.14.0-rc1" | ||||
| 	version = "1.14.1" | ||||
| 	githash string | ||||
|  | ||||
| 	flagConfig  = flag.String("conf", "matterbridge.toml", "config file") | ||||
|   | ||||
| @@ -913,6 +913,11 @@ QuoteDisable=false | ||||
| #OPTIONAL (default "{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})") | ||||
| QuoteFormat="{MESSAGE} (re @{QUOTENICK}: {QUOTEMESSAGE})" | ||||
|  | ||||
| #Convert WebP images to PNG before upload. | ||||
| #https://github.com/42wim/matterbridge/issues/398 | ||||
| #OPTIONAL (default false) | ||||
| MediaConvertWebPToPNG=false | ||||
|  | ||||
| #Disable sending of edits to other bridges | ||||
| #OPTIONAL (default false) | ||||
| EditDisable=false | ||||
| @@ -1002,9 +1007,10 @@ ShowTopicChange=false | ||||
| Server="https://yourrocketchatserver.domain.com:443" | ||||
|  | ||||
| #login/pass of your bot.  | ||||
| #login needs to be the login with email address! user@domain.com | ||||
| #Use a dedicated user for this and not your own!  | ||||
| #REQUIRED (when not using webhooks) | ||||
| Login="yourlogin" | ||||
| Login="yourlogin@domain.com" | ||||
| Password="yourpass" | ||||
|  | ||||
| #### Settings for webhook matterbridge. | ||||
| @@ -1045,6 +1051,8 @@ SkipTLSVerify=true | ||||
| #Useful if username overrides for incoming webhooks isn't enabled on the  | ||||
| #rocketchat server. If you set PrefixMessagesWithNick to true, each message  | ||||
| #from bridge to rocketchat will by default be prefixed by the RemoteNickFormat setting. i | ||||
| #if you're using login/pass you can better enable because of this bug: | ||||
| #https://github.com/RocketChat/Rocket.Chat/issues/7549 | ||||
| #OPTIONAL (default false) | ||||
| PrefixMessagesWithNick=false | ||||
|  | ||||
| @@ -1358,12 +1366,6 @@ Login="yourbot-bot@yourserver.zulipchat.com" | ||||
| #REQUIRED  | ||||
| Server="https://yourserver.zulipchat.com" | ||||
|  | ||||
| #Topic of the messages matterbridge will use | ||||
| #OPTIONAL (default "matterbridge") | ||||
| #You can specify a specific topic for each channel using [gateway.inout.options] | ||||
| #See more information below at the gateway configuration | ||||
| Topic="matterbridge" | ||||
|  | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| @@ -1603,7 +1605,7 @@ enable=true | ||||
|     #              if you specify an empty string bridge will list all the possibilities | ||||
|     #            - "Group Name" if you specify a group name the bridge will hint its JID to specify | ||||
|     #              as group names might change in time and contain weird emoticons | ||||
|     # zulip      - stream (without the #) | ||||
|     # zulip      - stream/topic:topicname (without the #) | ||||
|     #                   | ||||
|     # REQUIRED | ||||
|     channel="#testing" | ||||
| @@ -1645,10 +1647,7 @@ enable=true | ||||
|  | ||||
|     [[gateway.inout]] | ||||
|     account="zulip.streamchat" | ||||
|     channel="general" | ||||
|         #OPTIONAL - topic only works for zulip | ||||
|         [gateway.inout.options] | ||||
|         topic="topic1" | ||||
|     channel="general/topic:mytopic" | ||||
|  | ||||
|     #API example | ||||
|     #[[gateway.inout]] | ||||
|   | ||||
							
								
								
									
										1
									
								
								vendor/github.com/d5/tengo/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/d5/tengo/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| dist/ | ||||
							
								
								
									
										23
									
								
								vendor/github.com/d5/tengo/.goreleaser.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/d5/tengo/.goreleaser.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| builds: | ||||
|   - env: | ||||
|       - CGO_ENABLED=0 | ||||
|     main: ./cmd/tengo/main.go | ||||
|     goos: | ||||
|       - darwin | ||||
|       - linux | ||||
|       - windows | ||||
|   - env: | ||||
|       - CGO_ENABLED=0 | ||||
|     main: ./cmd/tengomin/main.go | ||||
|     binary: tengomin | ||||
|     goos: | ||||
|       - darwin | ||||
|       - linux | ||||
|       - windows | ||||
| archive: | ||||
|   files: | ||||
|     - none* | ||||
| checksum: | ||||
|   name_template: 'checksums.txt' | ||||
| changelog: | ||||
|   sort: asc | ||||
							
								
								
									
										17
									
								
								vendor/github.com/d5/tengo/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/d5/tengo/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| language: go | ||||
|  | ||||
| go: | ||||
|   - 1.9 | ||||
|  | ||||
| install: | ||||
|   - go get -u golang.org/x/lint/golint | ||||
|  | ||||
| script: | ||||
|   - make test | ||||
|  | ||||
| deploy: | ||||
|   - provider: script | ||||
|     skip_cleanup: true | ||||
|     script: curl -sL https://git.io/goreleaser | bash | ||||
|     on: | ||||
|       tags: true | ||||
							
								
								
									
										11
									
								
								vendor/github.com/d5/tengo/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/d5/tengo/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| vet: | ||||
| 	go vet ./... | ||||
|  | ||||
| lint: | ||||
| 	golint -set_exit_status ./... | ||||
|  | ||||
| test: vet lint | ||||
| 	go test -race -cover ./... | ||||
|  | ||||
| fmt: | ||||
| 	go fmt ./... | ||||
							
								
								
									
										74
									
								
								vendor/github.com/d5/tengo/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/d5/tengo/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| <p align="center"> | ||||
|   <img src="https://raw.githubusercontent.com/d5/tengolang.com/master/logo_400.png" width="200" height="200"> | ||||
| </p> | ||||
|  | ||||
| # The Tengo Language | ||||
|  | ||||
| [](https://godoc.org/github.com/d5/tengo/script) | ||||
| [](https://goreportcard.com/report/github.com/d5/tengo) | ||||
| [](https://travis-ci.org/d5/tengo) | ||||
| [](https://www.patreon.com/tengolang) | ||||
|  | ||||
| **Tengo is a small, dynamic, fast, secure script language for Go.**  | ||||
|  | ||||
| Tengo is **[fast](#benchmark)** and secure because it's compiled/executed as bytecode on stack-based VM that's written in native Go. | ||||
|  | ||||
| ```golang | ||||
| /* The Tengo Language */ | ||||
|  | ||||
| each := func(seq, fn) { | ||||
|     for x in seq { fn(x) } | ||||
| } | ||||
|  | ||||
| sum := func(init, seq) { | ||||
|     each(seq, func(x) { init += x }) | ||||
|     return init | ||||
| } | ||||
|  | ||||
| n := sum(0, [1, 2, 3])   // == 6 | ||||
| s := sum("", [1, 2, 3])  // == "123" | ||||
| ``` | ||||
|  | ||||
| > Run this code in the [Playground](https://tengolang.com/?s=d01cf9ed81daba939e26618530eb171f7397d9c9) | ||||
|  | ||||
| ## Features | ||||
|  | ||||
| - Simple and highly readable [Syntax](https://github.com/d5/tengo/blob/master/docs/tutorial.md) | ||||
|   - Dynamic typing with type coercion | ||||
|   - Higher-order functions and closures | ||||
|   - Immutable values | ||||
|   - Garbage collection | ||||
| - [Securely Embeddable](https://github.com/d5/tengo/blob/master/docs/interoperability.md) and [Extensible](https://github.com/d5/tengo/blob/master/docs/objects.md) | ||||
| - Compiler/runtime written in native Go _(no external deps or cgo)_ | ||||
| - Executable as a [standalone](https://github.com/d5/tengo/blob/master/docs/tengo-cli.md) language / REPL | ||||
|  | ||||
| ## Benchmark | ||||
|  | ||||
| | | fib(35) | fibt(35) |  Type  | | ||||
| | :--- |    ---: |     ---: |  :---: | | ||||
| | Go | `58ms` | `4ms` | Go (native) | | ||||
| | [**Tengo**](https://github.com/d5/tengo) | `4,180ms` | `5ms` | VM on Go | | ||||
| | Lua | `1,695ms` | `3ms` | Lua (native) | | ||||
| | [go-lua](https://github.com/Shopify/go-lua) | `5,163ms` | `5ms` | Lua VM on Go | | ||||
| | [GopherLua](https://github.com/yuin/gopher-lua) | `5,525ms` | `5ms` | Lua VM on Go | | ||||
| | Python | `3,097ms` | `27ms` | Python (native) | | ||||
| | [starlark-go](https://github.com/google/starlark-go) | `15,307ms` | `5ms` | Python-like Interpreter on Go | | ||||
| | [gpython](https://github.com/go-python/gpython) | `17,656ms` | `5ms` | Python Interpreter on Go | | ||||
| | [goja](https://github.com/dop251/goja) | `6,876ms` | `5ms` | JS VM on Go | | ||||
| | [otto](https://github.com/robertkrimen/otto) | `81,886ms` | `12ms` | JS Interpreter on Go | | ||||
| | [Anko](https://github.com/mattn/anko) | `97,517ms` | `14ms` | Interpreter on Go | | ||||
|  | ||||
| _* [fib(35)](https://github.com/d5/tengobench/blob/master/code/fib.tengo): Fibonacci(35)_   | ||||
| _* [fibt(35)](https://github.com/d5/tengobench/blob/master/code/fibtc.tengo): [tail-call](https://en.wikipedia.org/wiki/Tail_call) version of Fibonacci(35)_   | ||||
| _* **Go** does not read the source code from file, while all other cases do_   | ||||
| _* See [here](https://github.com/d5/tengobench) for commands/codes used_ | ||||
|  | ||||
| ## References | ||||
|  | ||||
| - [Language Syntax](https://github.com/d5/tengo/blob/master/docs/tutorial.md) | ||||
| - [Object Types](https://github.com/d5/tengo/blob/master/docs/objects.md) | ||||
| - [Runtime Types](https://github.com/d5/tengo/blob/master/docs/runtime-types.md) and [Operators](https://github.com/d5/tengo/blob/master/docs/operators.md) | ||||
| - [Builtin Functions](https://github.com/d5/tengo/blob/master/docs/builtins.md) | ||||
| - [Interoperability](https://github.com/d5/tengo/blob/master/docs/interoperability.md) | ||||
| - [Tengo CLI](https://github.com/d5/tengo/blob/master/docs/tengo-cli.md) | ||||
| - [Standard Library](https://github.com/d5/tengo/blob/master/docs/stdlib.md) | ||||
							
								
								
									
										24
									
								
								vendor/github.com/d5/tengo/compiler/compiler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								vendor/github.com/d5/tengo/compiler/compiler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -5,11 +5,11 @@ import ( | ||||
| 	"io" | ||||
| 	"reflect" | ||||
|  | ||||
| 	"github.com/d5/tengo" | ||||
| 	"github.com/d5/tengo/compiler/ast" | ||||
| 	"github.com/d5/tengo/compiler/source" | ||||
| 	"github.com/d5/tengo/compiler/token" | ||||
| 	"github.com/d5/tengo/objects" | ||||
| 	"github.com/d5/tengo/stdlib" | ||||
| ) | ||||
|  | ||||
| // Compiler compiles the AST into a bytecode. | ||||
| @@ -54,9 +54,6 @@ func NewCompiler(file *source.File, symbolTable *SymbolTable, constants []object | ||||
| 	// builtin modules | ||||
| 	if builtinModules == nil { | ||||
| 		builtinModules = make(map[string]bool) | ||||
| 		for name := range stdlib.Modules { | ||||
| 			builtinModules[name] = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &Compiler{ | ||||
| @@ -195,6 +192,10 @@ func (c *Compiler) Compile(node ast.Node) error { | ||||
| 		} | ||||
|  | ||||
| 	case *ast.StringLit: | ||||
| 		if len(node.Value) > tengo.MaxStringLen { | ||||
| 			return c.error(node, objects.ErrStringLimit) | ||||
| 		} | ||||
|  | ||||
| 		c.emit(node, OpConstant, c.addConstant(&objects.String{Value: node.Value})) | ||||
|  | ||||
| 	case *ast.CharLit: | ||||
| @@ -332,6 +333,9 @@ func (c *Compiler) Compile(node ast.Node) error { | ||||
| 	case *ast.MapLit: | ||||
| 		for _, elt := range node.Elements { | ||||
| 			// key | ||||
| 			if len(elt.Key) > tengo.MaxStringLen { | ||||
| 				return c.error(node, objects.ErrStringLimit) | ||||
| 			} | ||||
| 			c.emit(node, OpConstant, c.addConstant(&objects.String{Value: elt.Key})) | ||||
|  | ||||
| 			// value | ||||
| @@ -507,6 +511,10 @@ func (c *Compiler) Compile(node ast.Node) error { | ||||
|  | ||||
| 	case *ast.ImportExpr: | ||||
| 		if c.builtinModules[node.ModuleName] { | ||||
| 			if len(node.ModuleName) > tengo.MaxStringLen { | ||||
| 				return c.error(node, objects.ErrStringLimit) | ||||
| 			} | ||||
|  | ||||
| 			c.emit(node, OpConstant, c.addConstant(&objects.String{Value: node.ModuleName})) | ||||
| 			c.emit(node, OpGetBuiltinModule) | ||||
| 		} else { | ||||
| @@ -610,6 +618,14 @@ func (c *Compiler) fork(file *source.File, moduleName string, symbolTable *Symbo | ||||
| 	return child | ||||
| } | ||||
|  | ||||
| func (c *Compiler) error(node ast.Node, err error) error { | ||||
| 	return &Error{ | ||||
| 		fileSet: c.file.Set(), | ||||
| 		node:    node, | ||||
| 		error:   err, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *Compiler) errorf(node ast.Node, format string, args ...interface{}) error { | ||||
| 	return &Error{ | ||||
| 		fileSet: c.file.Set(), | ||||
|   | ||||
							
								
								
									
										7
									
								
								vendor/github.com/d5/tengo/compiler/compiler_module.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/d5/tengo/compiler/compiler_module.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -77,11 +77,8 @@ func (c *Compiler) doCompileModule(moduleName string, src []byte) (*objects.Comp | ||||
| 	symbolTable := NewSymbolTable() | ||||
|  | ||||
| 	// inherit builtin functions | ||||
| 	for idx, fn := range objects.Builtins { | ||||
| 		s, _, ok := c.symbolTable.Resolve(fn.Name) | ||||
| 		if ok && s.Scope == ScopeBuiltin { | ||||
| 			symbolTable.DefineBuiltin(idx, fn.Name) | ||||
| 		} | ||||
| 	for _, sym := range c.symbolTable.BuiltinSymbols() { | ||||
| 		symbolTable.DefineBuiltin(sym.Index, sym.Name) | ||||
| 	} | ||||
|  | ||||
| 	// no global scope for the module | ||||
|   | ||||
							
								
								
									
										28
									
								
								vendor/github.com/d5/tengo/compiler/parser/parse_file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/d5/tengo/compiler/parser/parse_file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,28 +0,0 @@ | ||||
| package parser | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
|  | ||||
| 	"github.com/d5/tengo/compiler/ast" | ||||
| 	"github.com/d5/tengo/compiler/source" | ||||
| ) | ||||
|  | ||||
| // ParseFile parses a file with a given src. | ||||
| func ParseFile(file *source.File, src []byte, trace io.Writer) (res *ast.File, err error) { | ||||
| 	p := NewParser(file, src, trace) | ||||
|  | ||||
| 	defer func() { | ||||
| 		if e := recover(); e != nil { | ||||
| 			if _, ok := e.(bailout); !ok { | ||||
| 				panic(e) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		p.errors.Sort() | ||||
| 		err = p.errors.Err() | ||||
| 	}() | ||||
|  | ||||
| 	res, err = p.ParseFile() | ||||
|  | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										3
									
								
								vendor/github.com/d5/tengo/compiler/parser/parse_source.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/d5/tengo/compiler/parser/parse_source.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -12,5 +12,6 @@ func ParseSource(filename string, src []byte, trace io.Writer) (res *ast.File, e | ||||
| 	fileSet := source.NewFileSet() | ||||
| 	file := fileSet.AddFile(filename, -1, len(src)) | ||||
|  | ||||
| 	return ParseFile(file, src, trace) | ||||
| 	p := NewParser(file, src, trace) | ||||
| 	return p.ParseFile() | ||||
| } | ||||
|   | ||||
							
								
								
									
										39
									
								
								vendor/github.com/d5/tengo/compiler/parser/parser.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/d5/tengo/compiler/parser/parser.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -57,7 +57,18 @@ func NewParser(file *source.File, src []byte, trace io.Writer) *Parser { | ||||
| } | ||||
|  | ||||
| // ParseFile parses the source and returns an AST file unit. | ||||
| func (p *Parser) ParseFile() (*ast.File, error) { | ||||
| func (p *Parser) ParseFile() (file *ast.File, err error) { | ||||
| 	defer func() { | ||||
| 		if e := recover(); e != nil { | ||||
| 			if _, ok := e.(bailout); !ok { | ||||
| 				panic(e) | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		p.errors.Sort() | ||||
| 		err = p.errors.Err() | ||||
| 	}() | ||||
|  | ||||
| 	if p.trace { | ||||
| 		defer un(trace(p, "File")) | ||||
| 	} | ||||
| @@ -71,10 +82,12 @@ func (p *Parser) ParseFile() (*ast.File, error) { | ||||
| 		return nil, p.errors.Err() | ||||
| 	} | ||||
|  | ||||
| 	return &ast.File{ | ||||
| 	file = &ast.File{ | ||||
| 		InputFile: p.file, | ||||
| 		Stmts:     stmts, | ||||
| 	}, nil | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (p *Parser) parseExpr() ast.Expr { | ||||
| @@ -1002,16 +1015,26 @@ func (p *Parser) parseMapElementLit() *ast.MapElementLit { | ||||
| 		defer un(trace(p, "MapElementLit")) | ||||
| 	} | ||||
|  | ||||
| 	// key: read identifier token but it's not actually an identifier | ||||
| 	ident := p.parseIdent() | ||||
| 	pos := p.pos | ||||
| 	name := "_" | ||||
|  | ||||
| 	if p.token == token.Ident { | ||||
| 		name = p.tokenLit | ||||
| 	} else if p.token == token.String { | ||||
| 		v, _ := strconv.Unquote(p.tokenLit) | ||||
| 		name = v | ||||
| 	} else { | ||||
| 		p.errorExpected(pos, "map key") | ||||
| 	} | ||||
|  | ||||
| 	p.next() | ||||
|  | ||||
| 	colonPos := p.expect(token.Colon) | ||||
|  | ||||
| 	valueExpr := p.parseExpr() | ||||
|  | ||||
| 	return &ast.MapElementLit{ | ||||
| 		Key:      ident.Name, | ||||
| 		KeyPos:   ident.NamePos, | ||||
| 		Key:      name, | ||||
| 		KeyPos:   pos, | ||||
| 		ColonPos: colonPos, | ||||
| 		Value:    valueExpr, | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										28
									
								
								vendor/github.com/d5/tengo/compiler/symbol_table.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										28
									
								
								vendor/github.com/d5/tengo/compiler/symbol_table.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,12 +2,13 @@ package compiler | ||||
|  | ||||
| // SymbolTable represents a symbol table. | ||||
| type SymbolTable struct { | ||||
| 	parent        *SymbolTable | ||||
| 	block         bool | ||||
| 	store         map[string]*Symbol | ||||
| 	numDefinition int | ||||
| 	maxDefinition int | ||||
| 	freeSymbols   []*Symbol | ||||
| 	parent         *SymbolTable | ||||
| 	block          bool | ||||
| 	store          map[string]*Symbol | ||||
| 	numDefinition  int | ||||
| 	maxDefinition  int | ||||
| 	freeSymbols    []*Symbol | ||||
| 	builtinSymbols []*Symbol | ||||
| } | ||||
|  | ||||
| // NewSymbolTable creates a SymbolTable. | ||||
| @@ -37,6 +38,10 @@ func (t *SymbolTable) Define(name string) *Symbol { | ||||
|  | ||||
| // DefineBuiltin adds a symbol for builtin function. | ||||
| func (t *SymbolTable) DefineBuiltin(index int, name string) *Symbol { | ||||
| 	if t.parent != nil { | ||||
| 		return t.parent.DefineBuiltin(index, name) | ||||
| 	} | ||||
|  | ||||
| 	symbol := &Symbol{ | ||||
| 		Name:  name, | ||||
| 		Index: index, | ||||
| @@ -45,6 +50,8 @@ func (t *SymbolTable) DefineBuiltin(index int, name string) *Symbol { | ||||
|  | ||||
| 	t.store[name] = symbol | ||||
|  | ||||
| 	t.builtinSymbols = append(t.builtinSymbols, symbol) | ||||
|  | ||||
| 	return symbol | ||||
| } | ||||
|  | ||||
| @@ -101,6 +108,15 @@ func (t *SymbolTable) FreeSymbols() []*Symbol { | ||||
| 	return t.freeSymbols | ||||
| } | ||||
|  | ||||
| // BuiltinSymbols returns builtin symbols for the scope. | ||||
| func (t *SymbolTable) BuiltinSymbols() []*Symbol { | ||||
| 	if t.parent != nil { | ||||
| 		return t.parent.BuiltinSymbols() | ||||
| 	} | ||||
|  | ||||
| 	return t.builtinSymbols | ||||
| } | ||||
|  | ||||
| // Names returns the name of all the symbols. | ||||
| func (t *SymbolTable) Names() []string { | ||||
| 	var names []string | ||||
|   | ||||
							
								
								
									
										14
									
								
								vendor/github.com/d5/tengo/objects/builtin_convert.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/d5/tengo/objects/builtin_convert.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,5 +1,7 @@ | ||||
| package objects | ||||
|  | ||||
| import "github.com/d5/tengo" | ||||
|  | ||||
| func builtinString(args ...Object) (Object, error) { | ||||
| 	argsLen := len(args) | ||||
| 	if !(argsLen == 1 || argsLen == 2) { | ||||
| @@ -12,6 +14,10 @@ func builtinString(args ...Object) (Object, error) { | ||||
|  | ||||
| 	v, ok := ToString(args[0]) | ||||
| 	if ok { | ||||
| 		if len(v) > tengo.MaxStringLen { | ||||
| 			return nil, ErrStringLimit | ||||
| 		} | ||||
|  | ||||
| 		return &String{Value: v}, nil | ||||
| 	} | ||||
|  | ||||
| @@ -117,11 +123,19 @@ func builtinBytes(args ...Object) (Object, error) { | ||||
|  | ||||
| 	// bytes(N) => create a new bytes with given size N | ||||
| 	if n, ok := args[0].(*Int); ok { | ||||
| 		if n.Value > int64(tengo.MaxBytesLen) { | ||||
| 			return nil, ErrBytesLimit | ||||
| 		} | ||||
|  | ||||
| 		return &Bytes{Value: make([]byte, int(n.Value))}, nil | ||||
| 	} | ||||
|  | ||||
| 	v, ok := ToByteSlice(args[0]) | ||||
| 	if ok { | ||||
| 		if len(v) > tengo.MaxBytesLen { | ||||
| 			return nil, ErrBytesLimit | ||||
| 		} | ||||
|  | ||||
| 		return &Bytes{Value: v}, nil | ||||
| 	} | ||||
|  | ||||
|   | ||||
							
								
								
									
										6
									
								
								vendor/github.com/d5/tengo/objects/builtin_json.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/d5/tengo/objects/builtin_json.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,6 +2,8 @@ package objects | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
|  | ||||
| 	"github.com/d5/tengo" | ||||
| ) | ||||
|  | ||||
| // to_json(v object) => bytes | ||||
| @@ -15,6 +17,10 @@ func builtinToJSON(args ...Object) (Object, error) { | ||||
| 		return &Error{Value: &String{Value: err.Error()}}, nil | ||||
| 	} | ||||
|  | ||||
| 	if len(res) > tengo.MaxBytesLen { | ||||
| 		return nil, ErrBytesLimit | ||||
| 	} | ||||
|  | ||||
| 	return &Bytes{Value: res}, nil | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										10
									
								
								vendor/github.com/d5/tengo/objects/builtin_print.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/d5/tengo/objects/builtin_print.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -2,6 +2,8 @@ package objects | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/d5/tengo" | ||||
| ) | ||||
|  | ||||
| // print(args...) | ||||
| @@ -71,5 +73,11 @@ func builtinSprintf(args ...Object) (Object, error) { | ||||
| 		formatArgs[idx] = objectToInterface(arg) | ||||
| 	} | ||||
|  | ||||
| 	return &String{Value: fmt.Sprintf(format.Value, formatArgs...)}, nil | ||||
| 	s := fmt.Sprintf(format.Value, formatArgs...) | ||||
|  | ||||
| 	if len(s) > tengo.MaxStringLen { | ||||
| 		return nil, ErrStringLimit | ||||
| 	} | ||||
|  | ||||
| 	return &String{Value: s}, nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										289
									
								
								vendor/github.com/d5/tengo/objects/builtins.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										289
									
								
								vendor/github.com/d5/tengo/objects/builtins.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,135 +1,164 @@ | ||||
| package objects | ||||
|  | ||||
| // NamedBuiltinFunc is a named builtin function. | ||||
| type NamedBuiltinFunc struct { | ||||
| 	Name string | ||||
| 	Func CallableFunc | ||||
| // Builtins contains all default builtin functions. | ||||
| // Use GetBuiltinFunctions instead of accessing Builtins directly. | ||||
| var Builtins = []BuiltinFunction{ | ||||
| 	{ | ||||
| 		Name:  "print", | ||||
| 		Value: builtinPrint, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "printf", | ||||
| 		Value: builtinPrintf, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "sprintf", | ||||
| 		Value: builtinSprintf, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "len", | ||||
| 		Value: builtinLen, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "copy", | ||||
| 		Value: builtinCopy, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "append", | ||||
| 		Value: builtinAppend, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "string", | ||||
| 		Value: builtinString, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "int", | ||||
| 		Value: builtinInt, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "bool", | ||||
| 		Value: builtinBool, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "float", | ||||
| 		Value: builtinFloat, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "char", | ||||
| 		Value: builtinChar, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "bytes", | ||||
| 		Value: builtinBytes, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "time", | ||||
| 		Value: builtinTime, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_int", | ||||
| 		Value: builtinIsInt, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_float", | ||||
| 		Value: builtinIsFloat, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_string", | ||||
| 		Value: builtinIsString, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_bool", | ||||
| 		Value: builtinIsBool, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_char", | ||||
| 		Value: builtinIsChar, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_bytes", | ||||
| 		Value: builtinIsBytes, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_array", | ||||
| 		Value: builtinIsArray, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_immutable_array", | ||||
| 		Value: builtinIsImmutableArray, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_map", | ||||
| 		Value: builtinIsMap, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_immutable_map", | ||||
| 		Value: builtinIsImmutableMap, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_time", | ||||
| 		Value: builtinIsTime, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_error", | ||||
| 		Value: builtinIsError, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_undefined", | ||||
| 		Value: builtinIsUndefined, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_function", | ||||
| 		Value: builtinIsFunction, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "is_callable", | ||||
| 		Value: builtinIsCallable, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "to_json", | ||||
| 		Value: builtinToJSON, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "from_json", | ||||
| 		Value: builtinFromJSON, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name:  "type_name", | ||||
| 		Value: builtinTypeName, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| // Builtins contains all default builtin functions. | ||||
| var Builtins = []NamedBuiltinFunc{ | ||||
| 	{ | ||||
| 		Name: "print", | ||||
| 		Func: builtinPrint, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "printf", | ||||
| 		Func: builtinPrintf, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "sprintf", | ||||
| 		Func: builtinSprintf, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "len", | ||||
| 		Func: builtinLen, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "copy", | ||||
| 		Func: builtinCopy, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "append", | ||||
| 		Func: builtinAppend, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "string", | ||||
| 		Func: builtinString, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "int", | ||||
| 		Func: builtinInt, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "bool", | ||||
| 		Func: builtinBool, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "float", | ||||
| 		Func: builtinFloat, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "char", | ||||
| 		Func: builtinChar, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "bytes", | ||||
| 		Func: builtinBytes, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "time", | ||||
| 		Func: builtinTime, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_int", | ||||
| 		Func: builtinIsInt, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_float", | ||||
| 		Func: builtinIsFloat, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_string", | ||||
| 		Func: builtinIsString, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_bool", | ||||
| 		Func: builtinIsBool, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_char", | ||||
| 		Func: builtinIsChar, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_bytes", | ||||
| 		Func: builtinIsBytes, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_array", | ||||
| 		Func: builtinIsArray, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_immutable_array", | ||||
| 		Func: builtinIsImmutableArray, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_map", | ||||
| 		Func: builtinIsMap, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_immutable_map", | ||||
| 		Func: builtinIsImmutableMap, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_time", | ||||
| 		Func: builtinIsTime, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_error", | ||||
| 		Func: builtinIsError, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_undefined", | ||||
| 		Func: builtinIsUndefined, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_function", | ||||
| 		Func: builtinIsFunction, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "is_callable", | ||||
| 		Func: builtinIsCallable, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "to_json", | ||||
| 		Func: builtinToJSON, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "from_json", | ||||
| 		Func: builtinFromJSON, | ||||
| 	}, | ||||
| 	{ | ||||
| 		Name: "type_name", | ||||
| 		Func: builtinTypeName, | ||||
| 	}, | ||||
| // AllBuiltinFunctionNames returns a list of all default builtin function names. | ||||
| func AllBuiltinFunctionNames() []string { | ||||
| 	var names []string | ||||
| 	for _, bf := range Builtins { | ||||
| 		names = append(names, bf.Name) | ||||
| 	} | ||||
| 	return names | ||||
| } | ||||
|  | ||||
| // GetBuiltinFunctions returns a slice of builtin function objects. | ||||
| // GetBuiltinFunctions removes the duplicate names, and, the returned builtin functions | ||||
| // are not guaranteed to be in the same order as names. | ||||
| func GetBuiltinFunctions(names ...string) []*BuiltinFunction { | ||||
| 	include := make(map[string]bool) | ||||
| 	for _, name := range names { | ||||
| 		include[name] = true | ||||
| 	} | ||||
|  | ||||
| 	var builtinFuncs []*BuiltinFunction | ||||
| 	for _, bf := range Builtins { | ||||
| 		if include[bf.Name] { | ||||
| 			bf := bf | ||||
| 			builtinFuncs = append(builtinFuncs, &bf) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return builtinFuncs | ||||
| } | ||||
|  | ||||
| // GetAllBuiltinFunctions returns all builtin functions. | ||||
| func GetAllBuiltinFunctions() []*BuiltinFunction { | ||||
| 	return GetBuiltinFunctions(AllBuiltinFunctionNames()...) | ||||
| } | ||||
|   | ||||
							
								
								
									
										5
									
								
								vendor/github.com/d5/tengo/objects/bytes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/d5/tengo/objects/bytes.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,6 +3,7 @@ package objects | ||||
| import ( | ||||
| 	"bytes" | ||||
|  | ||||
| 	"github.com/d5/tengo" | ||||
| 	"github.com/d5/tengo/compiler/token" | ||||
| ) | ||||
|  | ||||
| @@ -27,6 +28,10 @@ func (o *Bytes) BinaryOp(op token.Token, rhs Object) (Object, error) { | ||||
| 	case token.Add: | ||||
| 		switch rhs := rhs.(type) { | ||||
| 		case *Bytes: | ||||
| 			if len(o.Value)+len(rhs.Value) > tengo.MaxBytesLen { | ||||
| 				return nil, ErrBytesLimit | ||||
| 			} | ||||
|  | ||||
| 			return &Bytes{Value: append(o.Value, rhs.Value...)}, nil | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/d5/tengo/objects/callable_func.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/d5/tengo/objects/callable_func.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,4 +1,4 @@ | ||||
| package objects | ||||
|  | ||||
| // CallableFunc is a function signature for the callable functions. | ||||
| type CallableFunc func(args ...Object) (ret Object, err error) | ||||
| type CallableFunc = func(args ...Object) (ret Object, err error) | ||||
|   | ||||
							
								
								
									
										10
									
								
								vendor/github.com/d5/tengo/objects/conversion.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/d5/tengo/objects/conversion.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -4,6 +4,8 @@ import ( | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/d5/tengo" | ||||
| ) | ||||
|  | ||||
| // ToString will try to convert object o to string value. | ||||
| @@ -194,6 +196,9 @@ func FromInterface(v interface{}) (Object, error) { | ||||
| 	case nil: | ||||
| 		return UndefinedValue, nil | ||||
| 	case string: | ||||
| 		if len(v) > tengo.MaxStringLen { | ||||
| 			return nil, ErrStringLimit | ||||
| 		} | ||||
| 		return &String{Value: v}, nil | ||||
| 	case int64: | ||||
| 		return &Int{Value: v}, nil | ||||
| @@ -211,6 +216,9 @@ func FromInterface(v interface{}) (Object, error) { | ||||
| 	case float64: | ||||
| 		return &Float{Value: v}, nil | ||||
| 	case []byte: | ||||
| 		if len(v) > tengo.MaxBytesLen { | ||||
| 			return nil, ErrBytesLimit | ||||
| 		} | ||||
| 		return &Bytes{Value: v}, nil | ||||
| 	case error: | ||||
| 		return &Error{Value: &String{Value: v.Error()}}, nil | ||||
| @@ -243,6 +251,8 @@ func FromInterface(v interface{}) (Object, error) { | ||||
| 		return &Time{Value: v}, nil | ||||
| 	case Object: | ||||
| 		return v, nil | ||||
| 	case CallableFunc: | ||||
| 		return &UserFunction{Value: v}, nil | ||||
| 	} | ||||
|  | ||||
| 	return nil, fmt.Errorf("cannot convert to object: %T", v) | ||||
|   | ||||
							
								
								
									
										6
									
								
								vendor/github.com/d5/tengo/objects/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/d5/tengo/objects/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -20,6 +20,12 @@ var ErrInvalidOperator = errors.New("invalid operator") | ||||
| // ErrWrongNumArguments represents a wrong number of arguments error. | ||||
| var ErrWrongNumArguments = errors.New("wrong number of arguments") | ||||
|  | ||||
| // ErrBytesLimit represents an error where the size of bytes value exceeds the limit. | ||||
| var ErrBytesLimit = errors.New("exceeding bytes size limit") | ||||
|  | ||||
| // ErrStringLimit represents an error where the size of string value exceeds the limit. | ||||
| var ErrStringLimit = errors.New("exceeding string size limit") | ||||
|  | ||||
| // ErrInvalidArgumentType represents an invalid argument value type error. | ||||
| type ErrInvalidArgumentType struct { | ||||
| 	Name     string | ||||
|   | ||||
							
								
								
									
										10
									
								
								vendor/github.com/d5/tengo/objects/string.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								vendor/github.com/d5/tengo/objects/string.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,6 +3,7 @@ package objects | ||||
| import ( | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/d5/tengo" | ||||
| 	"github.com/d5/tengo/compiler/token" | ||||
| ) | ||||
|  | ||||
| @@ -28,9 +29,16 @@ func (o *String) BinaryOp(op token.Token, rhs Object) (Object, error) { | ||||
| 	case token.Add: | ||||
| 		switch rhs := rhs.(type) { | ||||
| 		case *String: | ||||
| 			if len(o.Value)+len(rhs.Value) > tengo.MaxStringLen { | ||||
| 				return nil, ErrStringLimit | ||||
| 			} | ||||
| 			return &String{Value: o.Value + rhs.Value}, nil | ||||
| 		default: | ||||
| 			return &String{Value: o.Value + rhs.String()}, nil | ||||
| 			rhsStr := rhs.String() | ||||
| 			if len(o.Value)+len(rhsStr) > tengo.MaxStringLen { | ||||
| 				return nil, ErrStringLimit | ||||
| 			} | ||||
| 			return &String{Value: o.Value + rhsStr}, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
							
								
								
									
										673
									
								
								vendor/github.com/d5/tengo/runtime/vm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										673
									
								
								vendor/github.com/d5/tengo/runtime/vm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										83
									
								
								vendor/github.com/d5/tengo/script/script.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										83
									
								
								vendor/github.com/d5/tengo/script/script.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -9,16 +9,15 @@ import ( | ||||
| 	"github.com/d5/tengo/compiler/source" | ||||
| 	"github.com/d5/tengo/objects" | ||||
| 	"github.com/d5/tengo/runtime" | ||||
| 	"github.com/d5/tengo/stdlib" | ||||
| ) | ||||
|  | ||||
| // Script can simplify compilation and execution of embedded scripts. | ||||
| type Script struct { | ||||
| 	variables         map[string]*Variable | ||||
| 	removedBuiltins   map[string]bool | ||||
| 	removedStdModules map[string]bool | ||||
| 	userModuleLoader  compiler.ModuleLoader | ||||
| 	input             []byte | ||||
| 	variables        map[string]*Variable | ||||
| 	builtinFuncs     []objects.Object | ||||
| 	builtinModules   map[string]*objects.Object | ||||
| 	userModuleLoader compiler.ModuleLoader | ||||
| 	input            []byte | ||||
| } | ||||
|  | ||||
| // New creates a Script instance with an input script. | ||||
| @@ -56,22 +55,28 @@ func (s *Script) Remove(name string) bool { | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // DisableBuiltinFunction disables a builtin function. | ||||
| func (s *Script) DisableBuiltinFunction(name string) { | ||||
| 	if s.removedBuiltins == nil { | ||||
| 		s.removedBuiltins = make(map[string]bool) | ||||
| // SetBuiltinFunctions allows to define builtin functions. | ||||
| func (s *Script) SetBuiltinFunctions(funcs []*objects.BuiltinFunction) { | ||||
| 	if funcs != nil { | ||||
| 		s.builtinFuncs = make([]objects.Object, len(funcs)) | ||||
| 		for idx, fn := range funcs { | ||||
| 			s.builtinFuncs[idx] = fn | ||||
| 		} | ||||
| 	} else { | ||||
| 		s.builtinFuncs = []objects.Object{} | ||||
| 	} | ||||
|  | ||||
| 	s.removedBuiltins[name] = true | ||||
| } | ||||
|  | ||||
| // DisableStdModule disables a standard library module. | ||||
| func (s *Script) DisableStdModule(name string) { | ||||
| 	if s.removedStdModules == nil { | ||||
| 		s.removedStdModules = make(map[string]bool) | ||||
| // SetBuiltinModules allows to define builtin modules. | ||||
| func (s *Script) SetBuiltinModules(modules map[string]*objects.ImmutableMap) { | ||||
| 	if modules != nil { | ||||
| 		s.builtinModules = make(map[string]*objects.Object, len(modules)) | ||||
| 		for k, mod := range modules { | ||||
| 			s.builtinModules[k] = objectPtr(mod) | ||||
| 		} | ||||
| 	} else { | ||||
| 		s.builtinModules = map[string]*objects.Object{} | ||||
| 	} | ||||
|  | ||||
| 	s.removedStdModules[name] = true | ||||
| } | ||||
|  | ||||
| // SetUserModuleLoader sets the user module loader for the compiler. | ||||
| @@ -81,7 +86,7 @@ func (s *Script) SetUserModuleLoader(loader compiler.ModuleLoader) { | ||||
|  | ||||
| // Compile compiles the script with all the defined variables, and, returns Compiled object. | ||||
| func (s *Script) Compile() (*Compiled, error) { | ||||
| 	symbolTable, stdModules, globals, err := s.prepCompile() | ||||
| 	symbolTable, builtinModules, globals, err := s.prepCompile() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| @@ -92,10 +97,10 @@ func (s *Script) Compile() (*Compiled, error) { | ||||
| 	p := parser.NewParser(srcFile, s.input, nil) | ||||
| 	file, err := p.ParseFile() | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("parse error: %s", err.Error()) | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	c := compiler.NewCompiler(srcFile, symbolTable, nil, stdModules, nil) | ||||
| 	c := compiler.NewCompiler(srcFile, symbolTable, nil, builtinModules, nil) | ||||
|  | ||||
| 	if s.userModuleLoader != nil { | ||||
| 		c.SetModuleLoader(s.userModuleLoader) | ||||
| @@ -107,7 +112,7 @@ func (s *Script) Compile() (*Compiled, error) { | ||||
|  | ||||
| 	return &Compiled{ | ||||
| 		symbolTable: symbolTable, | ||||
| 		machine:     runtime.NewVM(c.Bytecode(), globals, nil), | ||||
| 		machine:     runtime.NewVM(c.Bytecode(), globals, s.builtinFuncs, s.builtinModules), | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| @@ -136,24 +141,36 @@ func (s *Script) RunContext(ctx context.Context) (compiled *Compiled, err error) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (s *Script) prepCompile() (symbolTable *compiler.SymbolTable, stdModules map[string]bool, globals []*objects.Object, err error) { | ||||
| func (s *Script) prepCompile() (symbolTable *compiler.SymbolTable, builtinModules map[string]bool, globals []*objects.Object, err error) { | ||||
| 	var names []string | ||||
| 	for name := range s.variables { | ||||
| 		names = append(names, name) | ||||
| 	} | ||||
|  | ||||
| 	symbolTable = compiler.NewSymbolTable() | ||||
| 	for idx, fn := range objects.Builtins { | ||||
| 		if !s.removedBuiltins[fn.Name] { | ||||
| 			symbolTable.DefineBuiltin(idx, fn.Name) | ||||
|  | ||||
| 	if s.builtinFuncs == nil { | ||||
| 		s.builtinFuncs = make([]objects.Object, len(objects.Builtins)) | ||||
| 		for idx, fn := range objects.Builtins { | ||||
| 			s.builtinFuncs[idx] = &objects.BuiltinFunction{ | ||||
| 				Name:  fn.Name, | ||||
| 				Value: fn.Value, | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	stdModules = make(map[string]bool) | ||||
| 	for name := range stdlib.Modules { | ||||
| 		if !s.removedStdModules[name] { | ||||
| 			stdModules[name] = true | ||||
| 		} | ||||
| 	if s.builtinModules == nil { | ||||
| 		s.builtinModules = make(map[string]*objects.Object) | ||||
| 	} | ||||
|  | ||||
| 	for idx, fn := range s.builtinFuncs { | ||||
| 		f := fn.(*objects.BuiltinFunction) | ||||
| 		symbolTable.DefineBuiltin(idx, f.Name) | ||||
| 	} | ||||
|  | ||||
| 	builtinModules = make(map[string]bool) | ||||
| 	for name := range s.builtinModules { | ||||
| 		builtinModules[name] = true | ||||
| 	} | ||||
|  | ||||
| 	globals = make([]*objects.Object, runtime.GlobalsSize, runtime.GlobalsSize) | ||||
| @@ -178,3 +195,7 @@ func (s *Script) copyVariables() map[string]*Variable { | ||||
|  | ||||
| 	return vars | ||||
| } | ||||
|  | ||||
| func objectPtr(o objects.Object) *objects.Object { | ||||
| 	return &o | ||||
| } | ||||
|   | ||||
							
								
								
									
										11
									
								
								vendor/github.com/d5/tengo/stdlib/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/d5/tengo/stdlib/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,11 +0,0 @@ | ||||
| package stdlib | ||||
|  | ||||
| import "github.com/d5/tengo/objects" | ||||
|  | ||||
| func wrapError(err error) objects.Object { | ||||
| 	if err == nil { | ||||
| 		return objects.TrueValue | ||||
| 	} | ||||
|  | ||||
| 	return &objects.Error{Value: &objects.String{Value: err.Error()}} | ||||
| } | ||||
							
								
								
									
										1057
									
								
								vendor/github.com/d5/tengo/stdlib/func_typedefs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1057
									
								
								vendor/github.com/d5/tengo/stdlib/func_typedefs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										74
									
								
								vendor/github.com/d5/tengo/stdlib/math.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/d5/tengo/stdlib/math.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,74 +0,0 @@ | ||||
| package stdlib | ||||
|  | ||||
| import ( | ||||
| 	"math" | ||||
|  | ||||
| 	"github.com/d5/tengo/objects" | ||||
| ) | ||||
|  | ||||
| var mathModule = map[string]objects.Object{ | ||||
| 	"e":         &objects.Float{Value: math.E}, | ||||
| 	"pi":        &objects.Float{Value: math.Pi}, | ||||
| 	"phi":       &objects.Float{Value: math.Phi}, | ||||
| 	"sqrt2":     &objects.Float{Value: math.Sqrt2}, | ||||
| 	"sqrtE":     &objects.Float{Value: math.SqrtE}, | ||||
| 	"sqrtPi":    &objects.Float{Value: math.SqrtPi}, | ||||
| 	"sqrtPhi":   &objects.Float{Value: math.SqrtPhi}, | ||||
| 	"ln2":       &objects.Float{Value: math.Ln2}, | ||||
| 	"log2E":     &objects.Float{Value: math.Log2E}, | ||||
| 	"ln10":      &objects.Float{Value: math.Ln10}, | ||||
| 	"log10E":    &objects.Float{Value: math.Log10E}, | ||||
| 	"abs":       &objects.UserFunction{Name: "abs", Value: FuncAFRF(math.Abs)}, | ||||
| 	"acos":      &objects.UserFunction{Name: "acos", Value: FuncAFRF(math.Acos)}, | ||||
| 	"acosh":     &objects.UserFunction{Name: "acosh", Value: FuncAFRF(math.Acosh)}, | ||||
| 	"asin":      &objects.UserFunction{Name: "asin", Value: FuncAFRF(math.Asin)}, | ||||
| 	"asinh":     &objects.UserFunction{Name: "asinh", Value: FuncAFRF(math.Asinh)}, | ||||
| 	"atan":      &objects.UserFunction{Name: "atan", Value: FuncAFRF(math.Atan)}, | ||||
| 	"atan2":     &objects.UserFunction{Name: "atan2", Value: FuncAFFRF(math.Atan2)}, | ||||
| 	"atanh":     &objects.UserFunction{Name: "atanh", Value: FuncAFRF(math.Atanh)}, | ||||
| 	"cbrt":      &objects.UserFunction{Name: "cbrt", Value: FuncAFRF(math.Cbrt)}, | ||||
| 	"ceil":      &objects.UserFunction{Name: "ceil", Value: FuncAFRF(math.Ceil)}, | ||||
| 	"copysign":  &objects.UserFunction{Name: "copysign", Value: FuncAFFRF(math.Copysign)}, | ||||
| 	"cos":       &objects.UserFunction{Name: "cos", Value: FuncAFRF(math.Cos)}, | ||||
| 	"cosh":      &objects.UserFunction{Name: "cosh", Value: FuncAFRF(math.Cosh)}, | ||||
| 	"dim":       &objects.UserFunction{Name: "dim", Value: FuncAFFRF(math.Dim)}, | ||||
| 	"erf":       &objects.UserFunction{Name: "erf", Value: FuncAFRF(math.Erf)}, | ||||
| 	"erfc":      &objects.UserFunction{Name: "erfc", Value: FuncAFRF(math.Erfc)}, | ||||
| 	"exp":       &objects.UserFunction{Name: "exp", Value: FuncAFRF(math.Exp)}, | ||||
| 	"exp2":      &objects.UserFunction{Name: "exp2", Value: FuncAFRF(math.Exp2)}, | ||||
| 	"expm1":     &objects.UserFunction{Name: "expm1", Value: FuncAFRF(math.Expm1)}, | ||||
| 	"floor":     &objects.UserFunction{Name: "floor", Value: FuncAFRF(math.Floor)}, | ||||
| 	"gamma":     &objects.UserFunction{Name: "gamma", Value: FuncAFRF(math.Gamma)}, | ||||
| 	"hypot":     &objects.UserFunction{Name: "hypot", Value: FuncAFFRF(math.Hypot)}, | ||||
| 	"ilogb":     &objects.UserFunction{Name: "ilogb", Value: FuncAFRI(math.Ilogb)}, | ||||
| 	"inf":       &objects.UserFunction{Name: "inf", Value: FuncAIRF(math.Inf)}, | ||||
| 	"is_inf":    &objects.UserFunction{Name: "is_inf", Value: FuncAFIRB(math.IsInf)}, | ||||
| 	"is_nan":    &objects.UserFunction{Name: "is_nan", Value: FuncAFRB(math.IsNaN)}, | ||||
| 	"j0":        &objects.UserFunction{Name: "j0", Value: FuncAFRF(math.J0)}, | ||||
| 	"j1":        &objects.UserFunction{Name: "j1", Value: FuncAFRF(math.J1)}, | ||||
| 	"jn":        &objects.UserFunction{Name: "jn", Value: FuncAIFRF(math.Jn)}, | ||||
| 	"ldexp":     &objects.UserFunction{Name: "ldexp", Value: FuncAFIRF(math.Ldexp)}, | ||||
| 	"log":       &objects.UserFunction{Name: "log", Value: FuncAFRF(math.Log)}, | ||||
| 	"log10":     &objects.UserFunction{Name: "log10", Value: FuncAFRF(math.Log10)}, | ||||
| 	"log1p":     &objects.UserFunction{Name: "log1p", Value: FuncAFRF(math.Log1p)}, | ||||
| 	"log2":      &objects.UserFunction{Name: "log2", Value: FuncAFRF(math.Log2)}, | ||||
| 	"logb":      &objects.UserFunction{Name: "logb", Value: FuncAFRF(math.Logb)}, | ||||
| 	"max":       &objects.UserFunction{Name: "max", Value: FuncAFFRF(math.Max)}, | ||||
| 	"min":       &objects.UserFunction{Name: "min", Value: FuncAFFRF(math.Min)}, | ||||
| 	"mod":       &objects.UserFunction{Name: "mod", Value: FuncAFFRF(math.Mod)}, | ||||
| 	"nan":       &objects.UserFunction{Name: "nan", Value: FuncARF(math.NaN)}, | ||||
| 	"nextafter": &objects.UserFunction{Name: "nextafter", Value: FuncAFFRF(math.Nextafter)}, | ||||
| 	"pow":       &objects.UserFunction{Name: "pow", Value: FuncAFFRF(math.Pow)}, | ||||
| 	"pow10":     &objects.UserFunction{Name: "pow10", Value: FuncAIRF(math.Pow10)}, | ||||
| 	"remainder": &objects.UserFunction{Name: "remainder", Value: FuncAFFRF(math.Remainder)}, | ||||
| 	"signbit":   &objects.UserFunction{Name: "signbit", Value: FuncAFRB(math.Signbit)}, | ||||
| 	"sin":       &objects.UserFunction{Name: "sin", Value: FuncAFRF(math.Sin)}, | ||||
| 	"sinh":      &objects.UserFunction{Name: "sinh", Value: FuncAFRF(math.Sinh)}, | ||||
| 	"sqrt":      &objects.UserFunction{Name: "sqrt", Value: FuncAFRF(math.Sqrt)}, | ||||
| 	"tan":       &objects.UserFunction{Name: "tan", Value: FuncAFRF(math.Tan)}, | ||||
| 	"tanh":      &objects.UserFunction{Name: "tanh", Value: FuncAFRF(math.Tanh)}, | ||||
| 	"trunc":     &objects.UserFunction{Name: "trunc", Value: FuncAFRF(math.Trunc)}, | ||||
| 	"y0":        &objects.UserFunction{Name: "y0", Value: FuncAFRF(math.Y0)}, | ||||
| 	"y1":        &objects.UserFunction{Name: "y1", Value: FuncAFRF(math.Y1)}, | ||||
| 	"yn":        &objects.UserFunction{Name: "yn", Value: FuncAIFRF(math.Yn)}, | ||||
| } | ||||
							
								
								
									
										437
									
								
								vendor/github.com/d5/tengo/stdlib/os.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										437
									
								
								vendor/github.com/d5/tengo/stdlib/os.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,437 +0,0 @@ | ||||
| package stdlib | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
|  | ||||
| 	"github.com/d5/tengo/objects" | ||||
| ) | ||||
|  | ||||
| var osModule = map[string]objects.Object{ | ||||
| 	"o_rdonly":            &objects.Int{Value: int64(os.O_RDONLY)}, | ||||
| 	"o_wronly":            &objects.Int{Value: int64(os.O_WRONLY)}, | ||||
| 	"o_rdwr":              &objects.Int{Value: int64(os.O_RDWR)}, | ||||
| 	"o_append":            &objects.Int{Value: int64(os.O_APPEND)}, | ||||
| 	"o_create":            &objects.Int{Value: int64(os.O_CREATE)}, | ||||
| 	"o_excl":              &objects.Int{Value: int64(os.O_EXCL)}, | ||||
| 	"o_sync":              &objects.Int{Value: int64(os.O_SYNC)}, | ||||
| 	"o_trunc":             &objects.Int{Value: int64(os.O_TRUNC)}, | ||||
| 	"mode_dir":            &objects.Int{Value: int64(os.ModeDir)}, | ||||
| 	"mode_append":         &objects.Int{Value: int64(os.ModeAppend)}, | ||||
| 	"mode_exclusive":      &objects.Int{Value: int64(os.ModeExclusive)}, | ||||
| 	"mode_temporary":      &objects.Int{Value: int64(os.ModeTemporary)}, | ||||
| 	"mode_symlink":        &objects.Int{Value: int64(os.ModeSymlink)}, | ||||
| 	"mode_device":         &objects.Int{Value: int64(os.ModeDevice)}, | ||||
| 	"mode_named_pipe":     &objects.Int{Value: int64(os.ModeNamedPipe)}, | ||||
| 	"mode_socket":         &objects.Int{Value: int64(os.ModeSocket)}, | ||||
| 	"mode_setuid":         &objects.Int{Value: int64(os.ModeSetuid)}, | ||||
| 	"mode_setgui":         &objects.Int{Value: int64(os.ModeSetgid)}, | ||||
| 	"mode_char_device":    &objects.Int{Value: int64(os.ModeCharDevice)}, | ||||
| 	"mode_sticky":         &objects.Int{Value: int64(os.ModeSticky)}, | ||||
| 	"mode_type":           &objects.Int{Value: int64(os.ModeType)}, | ||||
| 	"mode_perm":           &objects.Int{Value: int64(os.ModePerm)}, | ||||
| 	"path_separator":      &objects.Char{Value: os.PathSeparator}, | ||||
| 	"path_list_separator": &objects.Char{Value: os.PathListSeparator}, | ||||
| 	"dev_null":            &objects.String{Value: os.DevNull}, | ||||
| 	"seek_set":            &objects.Int{Value: int64(io.SeekStart)}, | ||||
| 	"seek_cur":            &objects.Int{Value: int64(io.SeekCurrent)}, | ||||
| 	"seek_end":            &objects.Int{Value: int64(io.SeekEnd)}, | ||||
| 	"args":                &objects.UserFunction{Value: osArgs},                                           // args() => array(string) | ||||
| 	"chdir":               &objects.UserFunction{Name: "chdir", Value: FuncASRE(os.Chdir)},                // chdir(dir string) => error | ||||
| 	"chmod":               osFuncASFmRE(os.Chmod),                                                         // chmod(name string, mode int) => error | ||||
| 	"chown":               &objects.UserFunction{Name: "chown", Value: FuncASIIRE(os.Chown)},              // chown(name string, uid int, gid int) => error | ||||
| 	"clearenv":            &objects.UserFunction{Name: "clearenv", Value: FuncAR(os.Clearenv)},            // clearenv() | ||||
| 	"environ":             &objects.UserFunction{Name: "environ", Value: FuncARSs(os.Environ)},            // environ() => array(string) | ||||
| 	"exit":                &objects.UserFunction{Name: "exit", Value: FuncAIR(os.Exit)},                   // exit(code int) | ||||
| 	"expand_env":          &objects.UserFunction{Name: "expand_env", Value: FuncASRS(os.ExpandEnv)},       // expand_env(s string) => string | ||||
| 	"getegid":             &objects.UserFunction{Name: "getegid", Value: FuncARI(os.Getegid)},             // getegid() => int | ||||
| 	"getenv":              &objects.UserFunction{Name: "getenv", Value: FuncASRS(os.Getenv)},              // getenv(s string) => string | ||||
| 	"geteuid":             &objects.UserFunction{Name: "geteuid", Value: FuncARI(os.Geteuid)},             // geteuid() => int | ||||
| 	"getgid":              &objects.UserFunction{Name: "getgid", Value: FuncARI(os.Getgid)},               // getgid() => int | ||||
| 	"getgroups":           &objects.UserFunction{Name: "getgroups", Value: FuncARIsE(os.Getgroups)},       // getgroups() => array(string)/error | ||||
| 	"getpagesize":         &objects.UserFunction{Name: "getpagesize", Value: FuncARI(os.Getpagesize)},     // getpagesize() => int | ||||
| 	"getpid":              &objects.UserFunction{Name: "getpid", Value: FuncARI(os.Getpid)},               // getpid() => int | ||||
| 	"getppid":             &objects.UserFunction{Name: "getppid", Value: FuncARI(os.Getppid)},             // getppid() => int | ||||
| 	"getuid":              &objects.UserFunction{Name: "getuid", Value: FuncARI(os.Getuid)},               // getuid() => int | ||||
| 	"getwd":               &objects.UserFunction{Name: "getwd", Value: FuncARSE(os.Getwd)},                // getwd() => string/error | ||||
| 	"hostname":            &objects.UserFunction{Name: "hostname", Value: FuncARSE(os.Hostname)},          // hostname() => string/error | ||||
| 	"lchown":              &objects.UserFunction{Name: "lchown", Value: FuncASIIRE(os.Lchown)},            // lchown(name string, uid int, gid int) => error | ||||
| 	"link":                &objects.UserFunction{Name: "link", Value: FuncASSRE(os.Link)},                 // link(oldname string, newname string) => error | ||||
| 	"lookup_env":          &objects.UserFunction{Value: osLookupEnv},                                      // lookup_env(key string) => string/false | ||||
| 	"mkdir":               osFuncASFmRE(os.Mkdir),                                                         // mkdir(name string, perm int) => error | ||||
| 	"mkdir_all":           osFuncASFmRE(os.MkdirAll),                                                      // mkdir_all(name string, perm int) => error | ||||
| 	"readlink":            &objects.UserFunction{Name: "readlink", Value: FuncASRSE(os.Readlink)},         // readlink(name string) => string/error | ||||
| 	"remove":              &objects.UserFunction{Name: "remove", Value: FuncASRE(os.Remove)},              // remove(name string) => error | ||||
| 	"remove_all":          &objects.UserFunction{Name: "remove_all", Value: FuncASRE(os.RemoveAll)},       // remove_all(name string) => error | ||||
| 	"rename":              &objects.UserFunction{Name: "rename", Value: FuncASSRE(os.Rename)},             // rename(oldpath string, newpath string) => error | ||||
| 	"setenv":              &objects.UserFunction{Name: "setenv", Value: FuncASSRE(os.Setenv)},             // setenv(key string, value string) => error | ||||
| 	"symlink":             &objects.UserFunction{Name: "symlink", Value: FuncASSRE(os.Symlink)},           // symlink(oldname string newname string) => error | ||||
| 	"temp_dir":            &objects.UserFunction{Name: "temp_dir", Value: FuncARS(os.TempDir)},            // temp_dir() => string | ||||
| 	"truncate":            &objects.UserFunction{Name: "truncate", Value: FuncASI64RE(os.Truncate)},       // truncate(name string, size int) => error | ||||
| 	"unsetenv":            &objects.UserFunction{Name: "unsetenv", Value: FuncASRE(os.Unsetenv)},          // unsetenv(key string) => error | ||||
| 	"create":              &objects.UserFunction{Value: osCreate},                                         // create(name string) => imap(file)/error | ||||
| 	"open":                &objects.UserFunction{Value: osOpen},                                           // open(name string) => imap(file)/error | ||||
| 	"open_file":           &objects.UserFunction{Value: osOpenFile},                                       // open_file(name string, flag int, perm int) => imap(file)/error | ||||
| 	"find_process":        &objects.UserFunction{Value: osFindProcess},                                    // find_process(pid int) => imap(process)/error | ||||
| 	"start_process":       &objects.UserFunction{Value: osStartProcess},                                   // start_process(name string, argv array(string), dir string, env array(string)) => imap(process)/error | ||||
| 	"exec_look_path":      &objects.UserFunction{Name: "exec_look_path", Value: FuncASRSE(exec.LookPath)}, // exec_look_path(file) => string/error | ||||
| 	"exec":                &objects.UserFunction{Value: osExec},                                           // exec(name, args...) => command | ||||
| 	"stat":                &objects.UserFunction{Value: osStat},                                           // stat(name) => imap(fileinfo)/error | ||||
| 	"read_file":           &objects.UserFunction{Value: osReadFile},                                       // readfile(name) => array(byte)/error | ||||
| } | ||||
|  | ||||
| func osReadFile(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		return nil, objects.ErrWrongNumArguments | ||||
| 	} | ||||
|  | ||||
| 	fname, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	bytes, err := ioutil.ReadFile(fname) | ||||
| 	if err != nil { | ||||
| 		return wrapError(err), nil | ||||
| 	} | ||||
|  | ||||
| 	return &objects.Bytes{Value: bytes}, nil | ||||
| } | ||||
|  | ||||
| func osStat(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		return nil, objects.ErrWrongNumArguments | ||||
| 	} | ||||
|  | ||||
| 	fname, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	stat, err := os.Stat(fname) | ||||
| 	if err != nil { | ||||
| 		return wrapError(err), nil | ||||
| 	} | ||||
|  | ||||
| 	fstat := &objects.ImmutableMap{ | ||||
| 		Value: map[string]objects.Object{ | ||||
| 			"name":  &objects.String{Value: stat.Name()}, | ||||
| 			"mtime": &objects.Time{Value: stat.ModTime()}, | ||||
| 			"size":  &objects.Int{Value: stat.Size()}, | ||||
| 			"mode":  &objects.Int{Value: int64(stat.Mode())}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	if stat.IsDir() { | ||||
| 		fstat.Value["directory"] = objects.TrueValue | ||||
| 	} else { | ||||
| 		fstat.Value["directory"] = objects.FalseValue | ||||
| 	} | ||||
|  | ||||
| 	return fstat, nil | ||||
| } | ||||
|  | ||||
| func osCreate(args ...objects.Object) (objects.Object, error) { | ||||
| 	if len(args) != 1 { | ||||
| 		return nil, objects.ErrWrongNumArguments | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	res, err := os.Create(s1) | ||||
| 	if err != nil { | ||||
| 		return wrapError(err), nil | ||||
| 	} | ||||
|  | ||||
| 	return makeOSFile(res), nil | ||||
| } | ||||
|  | ||||
| func osOpen(args ...objects.Object) (objects.Object, error) { | ||||
| 	if len(args) != 1 { | ||||
| 		return nil, objects.ErrWrongNumArguments | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	res, err := os.Open(s1) | ||||
| 	if err != nil { | ||||
| 		return wrapError(err), nil | ||||
| 	} | ||||
|  | ||||
| 	return makeOSFile(res), nil | ||||
| } | ||||
|  | ||||
| func osOpenFile(args ...objects.Object) (objects.Object, error) { | ||||
| 	if len(args) != 3 { | ||||
| 		return nil, objects.ErrWrongNumArguments | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	i2, ok := objects.ToInt(args[1]) | ||||
| 	if !ok { | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	i3, ok := objects.ToInt(args[2]) | ||||
| 	if !ok { | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "third", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[2].TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	res, err := os.OpenFile(s1, i2, os.FileMode(i3)) | ||||
| 	if err != nil { | ||||
| 		return wrapError(err), nil | ||||
| 	} | ||||
|  | ||||
| 	return makeOSFile(res), nil | ||||
| } | ||||
|  | ||||
| func osArgs(args ...objects.Object) (objects.Object, error) { | ||||
| 	if len(args) != 0 { | ||||
| 		return nil, objects.ErrWrongNumArguments | ||||
| 	} | ||||
|  | ||||
| 	arr := &objects.Array{} | ||||
| 	for _, osArg := range os.Args { | ||||
| 		arr.Value = append(arr.Value, &objects.String{Value: osArg}) | ||||
| 	} | ||||
|  | ||||
| 	return arr, nil | ||||
| } | ||||
|  | ||||
| func osFuncASFmRE(fn func(string, os.FileMode) error) *objects.UserFunction { | ||||
| 	return &objects.UserFunction{ | ||||
| 		Value: func(args ...objects.Object) (objects.Object, error) { | ||||
| 			if len(args) != 2 { | ||||
| 				return nil, objects.ErrWrongNumArguments | ||||
| 			} | ||||
|  | ||||
| 			s1, ok := objects.ToString(args[0]) | ||||
| 			if !ok { | ||||
| 				return nil, objects.ErrInvalidArgumentType{ | ||||
| 					Name:     "first", | ||||
| 					Expected: "string(compatible)", | ||||
| 					Found:    args[0].TypeName(), | ||||
| 				} | ||||
| 			} | ||||
| 			i2, ok := objects.ToInt64(args[1]) | ||||
| 			if !ok { | ||||
| 				return nil, objects.ErrInvalidArgumentType{ | ||||
| 					Name:     "second", | ||||
| 					Expected: "int(compatible)", | ||||
| 					Found:    args[1].TypeName(), | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			return wrapError(fn(s1, os.FileMode(i2))), nil | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func osLookupEnv(args ...objects.Object) (objects.Object, error) { | ||||
| 	if len(args) != 1 { | ||||
| 		return nil, objects.ErrWrongNumArguments | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	res, ok := os.LookupEnv(s1) | ||||
| 	if !ok { | ||||
| 		return objects.FalseValue, nil | ||||
| 	} | ||||
|  | ||||
| 	return &objects.String{Value: res}, nil | ||||
| } | ||||
|  | ||||
| func osExec(args ...objects.Object) (objects.Object, error) { | ||||
| 	if len(args) == 0 { | ||||
| 		return nil, objects.ErrWrongNumArguments | ||||
| 	} | ||||
|  | ||||
| 	name, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var execArgs []string | ||||
| 	for idx, arg := range args[1:] { | ||||
| 		execArg, ok := objects.ToString(arg) | ||||
| 		if !ok { | ||||
| 			return nil, objects.ErrInvalidArgumentType{ | ||||
| 				Name:     fmt.Sprintf("args[%d]", idx), | ||||
| 				Expected: "string(compatible)", | ||||
| 				Found:    args[1+idx].TypeName(), | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		execArgs = append(execArgs, execArg) | ||||
| 	} | ||||
|  | ||||
| 	return makeOSExecCommand(exec.Command(name, execArgs...)), nil | ||||
| } | ||||
|  | ||||
| func osFindProcess(args ...objects.Object) (objects.Object, error) { | ||||
| 	if len(args) != 1 { | ||||
| 		return nil, objects.ErrWrongNumArguments | ||||
| 	} | ||||
|  | ||||
| 	i1, ok := objects.ToInt(args[0]) | ||||
| 	if !ok { | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	proc, err := os.FindProcess(i1) | ||||
| 	if err != nil { | ||||
| 		return wrapError(err), nil | ||||
| 	} | ||||
|  | ||||
| 	return makeOSProcess(proc), nil | ||||
| } | ||||
|  | ||||
| func osStartProcess(args ...objects.Object) (objects.Object, error) { | ||||
| 	if len(args) != 4 { | ||||
| 		return nil, objects.ErrWrongNumArguments | ||||
| 	} | ||||
|  | ||||
| 	name, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var argv []string | ||||
| 	var err error | ||||
| 	switch arg1 := args[1].(type) { | ||||
| 	case *objects.Array: | ||||
| 		argv, err = stringArray(arg1.Value, "second") | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	case *objects.ImmutableArray: | ||||
| 		argv, err = stringArray(arg1.Value, "second") | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	default: | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "array", | ||||
| 			Found:    arg1.TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	dir, ok := objects.ToString(args[2]) | ||||
| 	if !ok { | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "third", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[2].TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	var env []string | ||||
| 	switch arg3 := args[3].(type) { | ||||
| 	case *objects.Array: | ||||
| 		env, err = stringArray(arg3.Value, "fourth") | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	case *objects.ImmutableArray: | ||||
| 		env, err = stringArray(arg3.Value, "fourth") | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	default: | ||||
| 		return nil, objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "fourth", | ||||
| 			Expected: "array", | ||||
| 			Found:    arg3.TypeName(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	proc, err := os.StartProcess(name, argv, &os.ProcAttr{ | ||||
| 		Dir: dir, | ||||
| 		Env: env, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		return wrapError(err), nil | ||||
| 	} | ||||
|  | ||||
| 	return makeOSProcess(proc), nil | ||||
| } | ||||
|  | ||||
| func stringArray(arr []objects.Object, argName string) ([]string, error) { | ||||
| 	var sarr []string | ||||
| 	for idx, elem := range arr { | ||||
| 		str, ok := elem.(*objects.String) | ||||
| 		if !ok { | ||||
| 			return nil, objects.ErrInvalidArgumentType{ | ||||
| 				Name:     fmt.Sprintf("%s[%d]", argName, idx), | ||||
| 				Expected: "string", | ||||
| 				Found:    elem.TypeName(), | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		sarr = append(sarr, str.Value) | ||||
| 	} | ||||
|  | ||||
| 	return sarr, nil | ||||
| } | ||||
							
								
								
									
										109
									
								
								vendor/github.com/d5/tengo/stdlib/os_exec.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										109
									
								
								vendor/github.com/d5/tengo/stdlib/os_exec.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,109 +0,0 @@ | ||||
| package stdlib | ||||
|  | ||||
| import ( | ||||
| 	"os/exec" | ||||
|  | ||||
| 	"github.com/d5/tengo/objects" | ||||
| ) | ||||
|  | ||||
| func makeOSExecCommand(cmd *exec.Cmd) *objects.ImmutableMap { | ||||
| 	return &objects.ImmutableMap{ | ||||
| 		Value: map[string]objects.Object{ | ||||
| 			// combined_output() => bytes/error | ||||
| 			"combined_output": &objects.UserFunction{Name: "combined_output", Value: FuncARYE(cmd.CombinedOutput)}, // | ||||
| 			// output() => bytes/error | ||||
| 			"output": &objects.UserFunction{Name: "output", Value: FuncARYE(cmd.Output)}, // | ||||
| 			// run() => error | ||||
| 			"run": &objects.UserFunction{Name: "run", Value: FuncARE(cmd.Run)}, // | ||||
| 			// start() => error | ||||
| 			"start": &objects.UserFunction{Name: "start", Value: FuncARE(cmd.Start)}, // | ||||
| 			// wait() => error | ||||
| 			"wait": &objects.UserFunction{Name: "wait", Value: FuncARE(cmd.Wait)}, // | ||||
| 			// set_path(path string) | ||||
| 			"set_path": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					if len(args) != 1 { | ||||
| 						return nil, objects.ErrWrongNumArguments | ||||
| 					} | ||||
|  | ||||
| 					s1, ok := objects.ToString(args[0]) | ||||
| 					if !ok { | ||||
| 						return nil, objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "first", | ||||
| 							Expected: "string(compatible)", | ||||
| 							Found:    args[0].TypeName(), | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					cmd.Path = s1 | ||||
|  | ||||
| 					return objects.UndefinedValue, nil | ||||
| 				}, | ||||
| 			}, | ||||
| 			// set_dir(dir string) | ||||
| 			"set_dir": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					if len(args) != 1 { | ||||
| 						return nil, objects.ErrWrongNumArguments | ||||
| 					} | ||||
|  | ||||
| 					s1, ok := objects.ToString(args[0]) | ||||
| 					if !ok { | ||||
| 						return nil, objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "first", | ||||
| 							Expected: "string(compatible)", | ||||
| 							Found:    args[0].TypeName(), | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					cmd.Dir = s1 | ||||
|  | ||||
| 					return objects.UndefinedValue, nil | ||||
| 				}, | ||||
| 			}, | ||||
| 			// set_env(env array(string)) | ||||
| 			"set_env": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (objects.Object, error) { | ||||
| 					if len(args) != 1 { | ||||
| 						return nil, objects.ErrWrongNumArguments | ||||
| 					} | ||||
|  | ||||
| 					var env []string | ||||
| 					var err error | ||||
| 					switch arg0 := args[0].(type) { | ||||
| 					case *objects.Array: | ||||
| 						env, err = stringArray(arg0.Value, "first") | ||||
| 						if err != nil { | ||||
| 							return nil, err | ||||
| 						} | ||||
| 					case *objects.ImmutableArray: | ||||
| 						env, err = stringArray(arg0.Value, "first") | ||||
| 						if err != nil { | ||||
| 							return nil, err | ||||
| 						} | ||||
| 					default: | ||||
| 						return nil, objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "first", | ||||
| 							Expected: "array", | ||||
| 							Found:    arg0.TypeName(), | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					cmd.Env = env | ||||
|  | ||||
| 					return objects.UndefinedValue, nil | ||||
| 				}, | ||||
| 			}, | ||||
| 			// process() => imap(process) | ||||
| 			"process": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					if len(args) != 0 { | ||||
| 						return nil, objects.ErrWrongNumArguments | ||||
| 					} | ||||
|  | ||||
| 					return makeOSProcess(cmd.Process), nil | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										93
									
								
								vendor/github.com/d5/tengo/stdlib/os_file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										93
									
								
								vendor/github.com/d5/tengo/stdlib/os_file.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,93 +0,0 @@ | ||||
| package stdlib | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/d5/tengo/objects" | ||||
| ) | ||||
|  | ||||
| func makeOSFile(file *os.File) *objects.ImmutableMap { | ||||
| 	return &objects.ImmutableMap{ | ||||
| 		Value: map[string]objects.Object{ | ||||
| 			// chdir() => true/error | ||||
| 			"chdir": &objects.UserFunction{Name: "chdir", Value: FuncARE(file.Chdir)}, // | ||||
| 			// chown(uid int, gid int) => true/error | ||||
| 			"chown": &objects.UserFunction{Name: "chown", Value: FuncAIIRE(file.Chown)}, // | ||||
| 			// close() => error | ||||
| 			"close": &objects.UserFunction{Name: "close", Value: FuncARE(file.Close)}, // | ||||
| 			// name() => string | ||||
| 			"name": &objects.UserFunction{Name: "name", Value: FuncARS(file.Name)}, // | ||||
| 			// readdirnames(n int) => array(string)/error | ||||
| 			"readdirnames": &objects.UserFunction{Name: "readdirnames", Value: FuncAIRSsE(file.Readdirnames)}, // | ||||
| 			// sync() => error | ||||
| 			"sync": &objects.UserFunction{Name: "sync", Value: FuncARE(file.Sync)}, // | ||||
| 			// write(bytes) => int/error | ||||
| 			"write": &objects.UserFunction{Name: "write", Value: FuncAYRIE(file.Write)}, // | ||||
| 			// write(string) => int/error | ||||
| 			"write_string": &objects.UserFunction{Name: "write_string", Value: FuncASRIE(file.WriteString)}, // | ||||
| 			// read(bytes) => int/error | ||||
| 			"read": &objects.UserFunction{Name: "read", Value: FuncAYRIE(file.Read)}, // | ||||
| 			// chmod(mode int) => error | ||||
| 			"chmod": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					if len(args) != 1 { | ||||
| 						return nil, objects.ErrWrongNumArguments | ||||
| 					} | ||||
|  | ||||
| 					i1, ok := objects.ToInt64(args[0]) | ||||
| 					if !ok { | ||||
| 						return nil, objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "first", | ||||
| 							Expected: "int(compatible)", | ||||
| 							Found:    args[0].TypeName(), | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					return wrapError(file.Chmod(os.FileMode(i1))), nil | ||||
| 				}, | ||||
| 			}, | ||||
| 			// seek(offset int, whence int) => int/error | ||||
| 			"seek": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					if len(args) != 2 { | ||||
| 						return nil, objects.ErrWrongNumArguments | ||||
| 					} | ||||
|  | ||||
| 					i1, ok := objects.ToInt64(args[0]) | ||||
| 					if !ok { | ||||
| 						return nil, objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "first", | ||||
| 							Expected: "int(compatible)", | ||||
| 							Found:    args[0].TypeName(), | ||||
| 						} | ||||
| 					} | ||||
| 					i2, ok := objects.ToInt(args[1]) | ||||
| 					if !ok { | ||||
| 						return nil, objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "second", | ||||
| 							Expected: "int(compatible)", | ||||
| 							Found:    args[1].TypeName(), | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					res, err := file.Seek(i1, i2) | ||||
| 					if err != nil { | ||||
| 						return wrapError(err), nil | ||||
| 					} | ||||
|  | ||||
| 					return &objects.Int{Value: res}, nil | ||||
| 				}, | ||||
| 			}, | ||||
| 			// stat() => imap(fileinfo)/error | ||||
| 			"stat": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					if len(args) != 0 { | ||||
| 						return nil, objects.ErrWrongNumArguments | ||||
| 					} | ||||
|  | ||||
| 					return osStat(&objects.String{Value: file.Name()}) | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										60
									
								
								vendor/github.com/d5/tengo/stdlib/os_process.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								vendor/github.com/d5/tengo/stdlib/os_process.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,60 +0,0 @@ | ||||
| package stdlib | ||||
|  | ||||
| import ( | ||||
| 	"os" | ||||
| 	"syscall" | ||||
|  | ||||
| 	"github.com/d5/tengo/objects" | ||||
| ) | ||||
|  | ||||
| func makeOSProcessState(state *os.ProcessState) *objects.ImmutableMap { | ||||
| 	return &objects.ImmutableMap{ | ||||
| 		Value: map[string]objects.Object{ | ||||
| 			"exited":  &objects.UserFunction{Name: "exited", Value: FuncARB(state.Exited)},   // | ||||
| 			"pid":     &objects.UserFunction{Name: "pid", Value: FuncARI(state.Pid)},         // | ||||
| 			"string":  &objects.UserFunction{Name: "string", Value: FuncARS(state.String)},   // | ||||
| 			"success": &objects.UserFunction{Name: "success", Value: FuncARB(state.Success)}, // | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func makeOSProcess(proc *os.Process) *objects.ImmutableMap { | ||||
| 	return &objects.ImmutableMap{ | ||||
| 		Value: map[string]objects.Object{ | ||||
| 			"kill":    &objects.UserFunction{Name: "kill", Value: FuncARE(proc.Kill)},       // | ||||
| 			"release": &objects.UserFunction{Name: "release", Value: FuncARE(proc.Release)}, // | ||||
| 			"signal": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					if len(args) != 1 { | ||||
| 						return nil, objects.ErrWrongNumArguments | ||||
| 					} | ||||
|  | ||||
| 					i1, ok := objects.ToInt64(args[0]) | ||||
| 					if !ok { | ||||
| 						return nil, objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "first", | ||||
| 							Expected: "int(compatible)", | ||||
| 							Found:    args[0].TypeName(), | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					return wrapError(proc.Signal(syscall.Signal(i1))), nil | ||||
| 				}, | ||||
| 			}, | ||||
| 			"wait": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					if len(args) != 0 { | ||||
| 						return nil, objects.ErrWrongNumArguments | ||||
| 					} | ||||
|  | ||||
| 					state, err := proc.Wait() | ||||
| 					if err != nil { | ||||
| 						return wrapError(err), nil | ||||
| 					} | ||||
|  | ||||
| 					return makeOSProcessState(state), nil | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										99
									
								
								vendor/github.com/d5/tengo/stdlib/rand.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										99
									
								
								vendor/github.com/d5/tengo/stdlib/rand.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,99 +0,0 @@ | ||||
| package stdlib | ||||
|  | ||||
| import ( | ||||
| 	"math/rand" | ||||
|  | ||||
| 	"github.com/d5/tengo/objects" | ||||
| ) | ||||
|  | ||||
| var randModule = map[string]objects.Object{ | ||||
| 	"int":        &objects.UserFunction{Name: "int", Value: FuncARI64(rand.Int63)}, | ||||
| 	"float":      &objects.UserFunction{Name: "float", Value: FuncARF(rand.Float64)}, | ||||
| 	"intn":       &objects.UserFunction{Name: "intn", Value: FuncAI64RI64(rand.Int63n)}, | ||||
| 	"exp_float":  &objects.UserFunction{Name: "exp_float", Value: FuncARF(rand.ExpFloat64)}, | ||||
| 	"norm_float": &objects.UserFunction{Name: "norm_float", Value: FuncARF(rand.NormFloat64)}, | ||||
| 	"perm":       &objects.UserFunction{Name: "perm", Value: FuncAIRIs(rand.Perm)}, | ||||
| 	"seed":       &objects.UserFunction{Name: "seed", Value: FuncAI64R(rand.Seed)}, | ||||
| 	"read": &objects.UserFunction{ | ||||
| 		Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 			if len(args) != 1 { | ||||
| 				return nil, objects.ErrWrongNumArguments | ||||
| 			} | ||||
|  | ||||
| 			y1, ok := args[0].(*objects.Bytes) | ||||
| 			if !ok { | ||||
| 				return nil, objects.ErrInvalidArgumentType{ | ||||
| 					Name:     "first", | ||||
| 					Expected: "bytes", | ||||
| 					Found:    args[0].TypeName(), | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			res, err := rand.Read(y1.Value) | ||||
| 			if err != nil { | ||||
| 				ret = wrapError(err) | ||||
| 				return | ||||
| 			} | ||||
|  | ||||
| 			return &objects.Int{Value: int64(res)}, nil | ||||
| 		}, | ||||
| 	}, | ||||
| 	"rand": &objects.UserFunction{ | ||||
| 		Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 			if len(args) != 1 { | ||||
| 				return nil, objects.ErrWrongNumArguments | ||||
| 			} | ||||
|  | ||||
| 			i1, ok := objects.ToInt64(args[0]) | ||||
| 			if !ok { | ||||
| 				return nil, objects.ErrInvalidArgumentType{ | ||||
| 					Name:     "first", | ||||
| 					Expected: "int(compatible)", | ||||
| 					Found:    args[0].TypeName(), | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			src := rand.NewSource(i1) | ||||
|  | ||||
| 			return randRand(rand.New(src)), nil | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func randRand(r *rand.Rand) *objects.ImmutableMap { | ||||
| 	return &objects.ImmutableMap{ | ||||
| 		Value: map[string]objects.Object{ | ||||
| 			"int":        &objects.UserFunction{Name: "int", Value: FuncARI64(r.Int63)}, | ||||
| 			"float":      &objects.UserFunction{Name: "float", Value: FuncARF(r.Float64)}, | ||||
| 			"intn":       &objects.UserFunction{Name: "intn", Value: FuncAI64RI64(r.Int63n)}, | ||||
| 			"exp_float":  &objects.UserFunction{Name: "exp_float", Value: FuncARF(r.ExpFloat64)}, | ||||
| 			"norm_float": &objects.UserFunction{Name: "norm_float", Value: FuncARF(r.NormFloat64)}, | ||||
| 			"perm":       &objects.UserFunction{Name: "perm", Value: FuncAIRIs(r.Perm)}, | ||||
| 			"seed":       &objects.UserFunction{Name: "seed", Value: FuncAI64R(r.Seed)}, | ||||
| 			"read": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					if len(args) != 1 { | ||||
| 						return nil, objects.ErrWrongNumArguments | ||||
| 					} | ||||
|  | ||||
| 					y1, ok := args[0].(*objects.Bytes) | ||||
| 					if !ok { | ||||
| 						return nil, objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "first", | ||||
| 							Expected: "bytes", | ||||
| 							Found:    args[0].TypeName(), | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					res, err := r.Read(y1.Value) | ||||
| 					if err != nil { | ||||
| 						ret = wrapError(err) | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					return &objects.Int{Value: int64(res)}, nil | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										16
									
								
								vendor/github.com/d5/tengo/stdlib/stdlib.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/d5/tengo/stdlib/stdlib.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,16 +0,0 @@ | ||||
| package stdlib | ||||
|  | ||||
| import "github.com/d5/tengo/objects" | ||||
|  | ||||
| // Modules contain the standard modules. | ||||
| var Modules = map[string]*objects.Object{ | ||||
| 	"math":  objectPtr(&objects.ImmutableMap{Value: mathModule}), | ||||
| 	"os":    objectPtr(&objects.ImmutableMap{Value: osModule}), | ||||
| 	"text":  objectPtr(&objects.ImmutableMap{Value: textModule}), | ||||
| 	"times": objectPtr(&objects.ImmutableMap{Value: timesModule}), | ||||
| 	"rand":  objectPtr(&objects.ImmutableMap{Value: randModule}), | ||||
| } | ||||
|  | ||||
| func objectPtr(o objects.Object) *objects.Object { | ||||
| 	return &o | ||||
| } | ||||
							
								
								
									
										585
									
								
								vendor/github.com/d5/tengo/stdlib/text.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										585
									
								
								vendor/github.com/d5/tengo/stdlib/text.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,585 +0,0 @@ | ||||
| package stdlib | ||||
|  | ||||
| import ( | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/d5/tengo/objects" | ||||
| ) | ||||
|  | ||||
| var textModule = map[string]objects.Object{ | ||||
| 	"re_match":       &objects.UserFunction{Value: textREMatch},                                             // re_match(pattern, text) => bool/error | ||||
| 	"re_find":        &objects.UserFunction{Value: textREFind},                                              // re_find(pattern, text, count) => [[{text:,begin:,end:}]]/undefined | ||||
| 	"re_replace":     &objects.UserFunction{Value: textREReplace},                                           // re_replace(pattern, text, repl) => string/error | ||||
| 	"re_split":       &objects.UserFunction{Value: textRESplit},                                             // re_split(pattern, text, count) => [string]/error | ||||
| 	"re_compile":     &objects.UserFunction{Value: textRECompile},                                           // re_compile(pattern) => Regexp/error | ||||
| 	"compare":        &objects.UserFunction{Name: "compare", Value: FuncASSRI(strings.Compare)},             // compare(a, b) => int | ||||
| 	"contains":       &objects.UserFunction{Name: "contains", Value: FuncASSRB(strings.Contains)},           // contains(s, substr) => bool | ||||
| 	"contains_any":   &objects.UserFunction{Name: "contains_any", Value: FuncASSRB(strings.ContainsAny)},    // contains_any(s, chars) => bool | ||||
| 	"count":          &objects.UserFunction{Name: "count", Value: FuncASSRI(strings.Count)},                 // count(s, substr) => int | ||||
| 	"equal_fold":     &objects.UserFunction{Name: "equal_fold", Value: FuncASSRB(strings.EqualFold)},        // "equal_fold(s, t) => bool | ||||
| 	"fields":         &objects.UserFunction{Name: "fields", Value: FuncASRSs(strings.Fields)},               // fields(s) => [string] | ||||
| 	"has_prefix":     &objects.UserFunction{Name: "has_prefix", Value: FuncASSRB(strings.HasPrefix)},        // has_prefix(s, prefix) => bool | ||||
| 	"has_suffix":     &objects.UserFunction{Name: "has_suffix", Value: FuncASSRB(strings.HasSuffix)},        // has_suffix(s, suffix) => bool | ||||
| 	"index":          &objects.UserFunction{Name: "index", Value: FuncASSRI(strings.Index)},                 // index(s, substr) => int | ||||
| 	"index_any":      &objects.UserFunction{Name: "index_any", Value: FuncASSRI(strings.IndexAny)},          // index_any(s, chars) => int | ||||
| 	"join":           &objects.UserFunction{Name: "join", Value: FuncASsSRS(strings.Join)},                  // join(arr, sep) => string | ||||
| 	"last_index":     &objects.UserFunction{Name: "last_index", Value: FuncASSRI(strings.LastIndex)},        // last_index(s, substr) => int | ||||
| 	"last_index_any": &objects.UserFunction{Name: "last_index_any", Value: FuncASSRI(strings.LastIndexAny)}, // last_index_any(s, chars) => int | ||||
| 	"repeat":         &objects.UserFunction{Name: "repeat", Value: FuncASIRS(strings.Repeat)},               // repeat(s, count) => string | ||||
| 	"replace":        &objects.UserFunction{Value: textReplace},                                             // replace(s, old, new, n) => string | ||||
| 	"split":          &objects.UserFunction{Name: "split", Value: FuncASSRSs(strings.Split)},                // split(s, sep) => [string] | ||||
| 	"split_after":    &objects.UserFunction{Name: "split_after", Value: FuncASSRSs(strings.SplitAfter)},     // split_after(s, sep) => [string] | ||||
| 	"split_after_n":  &objects.UserFunction{Name: "split_after_n", Value: FuncASSIRSs(strings.SplitAfterN)}, // split_after_n(s, sep, n) => [string] | ||||
| 	"split_n":        &objects.UserFunction{Name: "split_n", Value: FuncASSIRSs(strings.SplitN)},            // split_n(s, sep, n) => [string] | ||||
| 	"title":          &objects.UserFunction{Name: "title", Value: FuncASRS(strings.Title)},                  // title(s) => string | ||||
| 	"to_lower":       &objects.UserFunction{Name: "to_lower", Value: FuncASRS(strings.ToLower)},             // to_lower(s) => string | ||||
| 	"to_title":       &objects.UserFunction{Name: "to_title", Value: FuncASRS(strings.ToTitle)},             // to_title(s) => string | ||||
| 	"to_upper":       &objects.UserFunction{Name: "to_upper", Value: FuncASRS(strings.ToUpper)},             // to_upper(s) => string | ||||
| 	"trim_left":      &objects.UserFunction{Name: "trim_left", Value: FuncASSRS(strings.TrimLeft)},          // trim_left(s, cutset) => string | ||||
| 	"trim_prefix":    &objects.UserFunction{Name: "trim_prefix", Value: FuncASSRS(strings.TrimPrefix)},      // trim_prefix(s, prefix) => string | ||||
| 	"trim_right":     &objects.UserFunction{Name: "trim_right", Value: FuncASSRS(strings.TrimRight)},        // trim_right(s, cutset) => string | ||||
| 	"trim_space":     &objects.UserFunction{Name: "trim_space", Value: FuncASRS(strings.TrimSpace)},         // trim_space(s) => string | ||||
| 	"trim_suffix":    &objects.UserFunction{Name: "trim_suffix", Value: FuncASSRS(strings.TrimSuffix)},      // trim_suffix(s, suffix) => string | ||||
| 	"atoi":           &objects.UserFunction{Name: "atoi", Value: FuncASRIE(strconv.Atoi)},                   // atoi(str) => int/error | ||||
| 	"format_bool":    &objects.UserFunction{Value: textFormatBool},                                          // format_bool(b) => string | ||||
| 	"format_float":   &objects.UserFunction{Value: textFormatFloat},                                         // format_float(f, fmt, prec, bits) => string | ||||
| 	"format_int":     &objects.UserFunction{Value: textFormatInt},                                           // format_int(i, base) => string | ||||
| 	"itoa":           &objects.UserFunction{Name: "itoa", Value: FuncAIRS(strconv.Itoa)},                    // itoa(i) => string | ||||
| 	"parse_bool":     &objects.UserFunction{Value: textParseBool},                                           // parse_bool(str) => bool/error | ||||
| 	"parse_float":    &objects.UserFunction{Value: textParseFloat},                                          // parse_float(str, bits) => float/error | ||||
| 	"parse_int":      &objects.UserFunction{Value: textParseInt},                                            // parse_int(str, base, bits) => int/error | ||||
| 	"quote":          &objects.UserFunction{Name: "quote", Value: FuncASRS(strconv.Quote)},                  // quote(str) => string | ||||
| 	"unquote":        &objects.UserFunction{Name: "unquote", Value: FuncASRSE(strconv.Unquote)},             // unquote(str) => string/error | ||||
| } | ||||
|  | ||||
| func textREMatch(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 2 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s2, ok := objects.ToString(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	matched, err := regexp.MatchString(s1, s2) | ||||
| 	if err != nil { | ||||
| 		ret = wrapError(err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if matched { | ||||
| 		ret = objects.TrueValue | ||||
| 	} else { | ||||
| 		ret = objects.FalseValue | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func textREFind(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	numArgs := len(args) | ||||
| 	if numArgs != 2 && numArgs != 3 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	re, err := regexp.Compile(s1) | ||||
| 	if err != nil { | ||||
| 		ret = wrapError(err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s2, ok := objects.ToString(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if numArgs < 3 { | ||||
| 		m := re.FindStringSubmatchIndex(s2) | ||||
| 		if m == nil { | ||||
| 			ret = objects.UndefinedValue | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		arr := &objects.Array{} | ||||
| 		for i := 0; i < len(m); i += 2 { | ||||
| 			arr.Value = append(arr.Value, &objects.ImmutableMap{Value: map[string]objects.Object{ | ||||
| 				"text":  &objects.String{Value: s2[m[i]:m[i+1]]}, | ||||
| 				"begin": &objects.Int{Value: int64(m[i])}, | ||||
| 				"end":   &objects.Int{Value: int64(m[i+1])}, | ||||
| 			}}) | ||||
| 		} | ||||
|  | ||||
| 		ret = &objects.Array{Value: []objects.Object{arr}} | ||||
|  | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i3, ok := objects.ToInt(args[2]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "third", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[2].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	m := re.FindAllStringSubmatchIndex(s2, i3) | ||||
| 	if m == nil { | ||||
| 		ret = objects.UndefinedValue | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	arr := &objects.Array{} | ||||
| 	for _, m := range m { | ||||
| 		subMatch := &objects.Array{} | ||||
| 		for i := 0; i < len(m); i += 2 { | ||||
| 			subMatch.Value = append(subMatch.Value, &objects.ImmutableMap{Value: map[string]objects.Object{ | ||||
| 				"text":  &objects.String{Value: s2[m[i]:m[i+1]]}, | ||||
| 				"begin": &objects.Int{Value: int64(m[i])}, | ||||
| 				"end":   &objects.Int{Value: int64(m[i+1])}, | ||||
| 			}}) | ||||
| 		} | ||||
|  | ||||
| 		arr.Value = append(arr.Value, subMatch) | ||||
| 	} | ||||
|  | ||||
| 	ret = arr | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func textREReplace(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 3 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s2, ok := objects.ToString(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s3, ok := objects.ToString(args[2]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "third", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[2].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	re, err := regexp.Compile(s1) | ||||
| 	if err != nil { | ||||
| 		ret = wrapError(err) | ||||
| 	} else { | ||||
| 		ret = &objects.String{Value: re.ReplaceAllString(s2, s3)} | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func textRESplit(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	numArgs := len(args) | ||||
| 	if numArgs != 2 && numArgs != 3 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s2, ok := objects.ToString(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	var i3 = -1 | ||||
| 	if numArgs > 2 { | ||||
| 		i3, ok = objects.ToInt(args[2]) | ||||
| 		if !ok { | ||||
| 			err = objects.ErrInvalidArgumentType{ | ||||
| 				Name:     "third", | ||||
| 				Expected: "int(compatible)", | ||||
| 				Found:    args[2].TypeName(), | ||||
| 			} | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	re, err := regexp.Compile(s1) | ||||
| 	if err != nil { | ||||
| 		ret = wrapError(err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	arr := &objects.Array{} | ||||
| 	for _, s := range re.Split(s2, i3) { | ||||
| 		arr.Value = append(arr.Value, &objects.String{Value: s}) | ||||
| 	} | ||||
|  | ||||
| 	ret = arr | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func textRECompile(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	re, err := regexp.Compile(s1) | ||||
| 	if err != nil { | ||||
| 		ret = wrapError(err) | ||||
| 	} else { | ||||
| 		ret = makeTextRegexp(re) | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func textReplace(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 4 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s2, ok := objects.ToString(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s3, ok := objects.ToString(args[2]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "third", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[2].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i4, ok := objects.ToInt(args[3]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "fourth", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[3].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.String{Value: strings.Replace(s1, s2, s3, i4)} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func textFormatBool(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	b1, ok := args[0].(*objects.Bool) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "bool", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if b1 == objects.TrueValue { | ||||
| 		ret = &objects.String{Value: "true"} | ||||
| 	} else { | ||||
| 		ret = &objects.String{Value: "false"} | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func textFormatFloat(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 4 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	f1, ok := args[0].(*objects.Float) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "float", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s2, ok := objects.ToString(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i3, ok := objects.ToInt(args[2]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "third", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[2].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i4, ok := objects.ToInt(args[3]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "fourth", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[3].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.String{Value: strconv.FormatFloat(f1.Value, s2[0], i3, i4)} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func textFormatInt(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 2 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i1, ok := args[0].(*objects.Int) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "int", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i2, ok := objects.ToInt(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.String{Value: strconv.FormatInt(i1.Value, i2)} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func textParseBool(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := args[0].(*objects.String) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	parsed, err := strconv.ParseBool(s1.Value) | ||||
| 	if err != nil { | ||||
| 		ret = wrapError(err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if parsed { | ||||
| 		ret = objects.TrueValue | ||||
| 	} else { | ||||
| 		ret = objects.FalseValue | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func textParseFloat(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 2 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := args[0].(*objects.String) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i2, ok := objects.ToInt(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	parsed, err := strconv.ParseFloat(s1.Value, i2) | ||||
| 	if err != nil { | ||||
| 		ret = wrapError(err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Float{Value: parsed} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func textParseInt(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 3 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := args[0].(*objects.String) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i2, ok := objects.ToInt(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i3, ok := objects.ToInt(args[2]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "third", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[2].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	parsed, err := strconv.ParseInt(s1.Value, i2, i3) | ||||
| 	if err != nil { | ||||
| 		ret = wrapError(err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: parsed} | ||||
|  | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										195
									
								
								vendor/github.com/d5/tengo/stdlib/text_regexp.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										195
									
								
								vendor/github.com/d5/tengo/stdlib/text_regexp.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,195 +0,0 @@ | ||||
| package stdlib | ||||
|  | ||||
| import ( | ||||
| 	"regexp" | ||||
|  | ||||
| 	"github.com/d5/tengo/objects" | ||||
| ) | ||||
|  | ||||
| func makeTextRegexp(re *regexp.Regexp) *objects.ImmutableMap { | ||||
| 	return &objects.ImmutableMap{ | ||||
| 		Value: map[string]objects.Object{ | ||||
| 			// match(text) => bool | ||||
| 			"match": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					if len(args) != 1 { | ||||
| 						err = objects.ErrWrongNumArguments | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					s1, ok := objects.ToString(args[0]) | ||||
| 					if !ok { | ||||
| 						err = objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "first", | ||||
| 							Expected: "string(compatible)", | ||||
| 							Found:    args[0].TypeName(), | ||||
| 						} | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					if re.MatchString(s1) { | ||||
| 						ret = objects.TrueValue | ||||
| 					} else { | ||||
| 						ret = objects.FalseValue | ||||
| 					} | ||||
|  | ||||
| 					return | ||||
| 				}, | ||||
| 			}, | ||||
|  | ||||
| 			// find(text) 			=> array(array({text:,begin:,end:}))/undefined | ||||
| 			// find(text, maxCount) => array(array({text:,begin:,end:}))/undefined | ||||
| 			"find": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					numArgs := len(args) | ||||
| 					if numArgs != 1 && numArgs != 2 { | ||||
| 						err = objects.ErrWrongNumArguments | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					s1, ok := objects.ToString(args[0]) | ||||
| 					if !ok { | ||||
| 						err = objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "first", | ||||
| 							Expected: "string(compatible)", | ||||
| 							Found:    args[0].TypeName(), | ||||
| 						} | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					if numArgs == 1 { | ||||
| 						m := re.FindStringSubmatchIndex(s1) | ||||
| 						if m == nil { | ||||
| 							ret = objects.UndefinedValue | ||||
| 							return | ||||
| 						} | ||||
|  | ||||
| 						arr := &objects.Array{} | ||||
| 						for i := 0; i < len(m); i += 2 { | ||||
| 							arr.Value = append(arr.Value, &objects.ImmutableMap{Value: map[string]objects.Object{ | ||||
| 								"text":  &objects.String{Value: s1[m[i]:m[i+1]]}, | ||||
| 								"begin": &objects.Int{Value: int64(m[i])}, | ||||
| 								"end":   &objects.Int{Value: int64(m[i+1])}, | ||||
| 							}}) | ||||
| 						} | ||||
|  | ||||
| 						ret = &objects.Array{Value: []objects.Object{arr}} | ||||
|  | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					i2, ok := objects.ToInt(args[1]) | ||||
| 					if !ok { | ||||
| 						err = objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "second", | ||||
| 							Expected: "int(compatible)", | ||||
| 							Found:    args[1].TypeName(), | ||||
| 						} | ||||
| 						return | ||||
| 					} | ||||
| 					m := re.FindAllStringSubmatchIndex(s1, i2) | ||||
| 					if m == nil { | ||||
| 						ret = objects.UndefinedValue | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					arr := &objects.Array{} | ||||
| 					for _, m := range m { | ||||
| 						subMatch := &objects.Array{} | ||||
| 						for i := 0; i < len(m); i += 2 { | ||||
| 							subMatch.Value = append(subMatch.Value, &objects.ImmutableMap{Value: map[string]objects.Object{ | ||||
| 								"text":  &objects.String{Value: s1[m[i]:m[i+1]]}, | ||||
| 								"begin": &objects.Int{Value: int64(m[i])}, | ||||
| 								"end":   &objects.Int{Value: int64(m[i+1])}, | ||||
| 							}}) | ||||
| 						} | ||||
|  | ||||
| 						arr.Value = append(arr.Value, subMatch) | ||||
| 					} | ||||
|  | ||||
| 					ret = arr | ||||
|  | ||||
| 					return | ||||
| 				}, | ||||
| 			}, | ||||
|  | ||||
| 			// replace(src, repl) => string | ||||
| 			"replace": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					if len(args) != 2 { | ||||
| 						err = objects.ErrWrongNumArguments | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					s1, ok := objects.ToString(args[0]) | ||||
| 					if !ok { | ||||
| 						err = objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "first", | ||||
| 							Expected: "string(compatible)", | ||||
| 							Found:    args[0].TypeName(), | ||||
| 						} | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					s2, ok := objects.ToString(args[1]) | ||||
| 					if !ok { | ||||
| 						err = objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "second", | ||||
| 							Expected: "string(compatible)", | ||||
| 							Found:    args[1].TypeName(), | ||||
| 						} | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					ret = &objects.String{Value: re.ReplaceAllString(s1, s2)} | ||||
|  | ||||
| 					return | ||||
| 				}, | ||||
| 			}, | ||||
|  | ||||
| 			// split(text) 			 => array(string) | ||||
| 			// split(text, maxCount) => array(string) | ||||
| 			"split": &objects.UserFunction{ | ||||
| 				Value: func(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 					numArgs := len(args) | ||||
| 					if numArgs != 1 && numArgs != 2 { | ||||
| 						err = objects.ErrWrongNumArguments | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					s1, ok := objects.ToString(args[0]) | ||||
| 					if !ok { | ||||
| 						err = objects.ErrInvalidArgumentType{ | ||||
| 							Name:     "first", | ||||
| 							Expected: "string(compatible)", | ||||
| 							Found:    args[0].TypeName(), | ||||
| 						} | ||||
| 						return | ||||
| 					} | ||||
|  | ||||
| 					var i2 = -1 | ||||
| 					if numArgs > 1 { | ||||
| 						i2, ok = objects.ToInt(args[1]) | ||||
| 						if !ok { | ||||
| 							err = objects.ErrInvalidArgumentType{ | ||||
| 								Name:     "second", | ||||
| 								Expected: "int(compatible)", | ||||
| 								Found:    args[1].TypeName(), | ||||
| 							} | ||||
| 							return | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
| 					arr := &objects.Array{} | ||||
| 					for _, s := range re.Split(s1, i2) { | ||||
| 						arr.Value = append(arr.Value, &objects.String{Value: s}) | ||||
| 					} | ||||
|  | ||||
| 					ret = arr | ||||
|  | ||||
| 					return | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										982
									
								
								vendor/github.com/d5/tengo/stdlib/times.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										982
									
								
								vendor/github.com/d5/tengo/stdlib/times.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,982 +0,0 @@ | ||||
| package stdlib | ||||
|  | ||||
| import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/d5/tengo/objects" | ||||
| ) | ||||
|  | ||||
| var timesModule = map[string]objects.Object{ | ||||
| 	"format_ansic":         &objects.String{Value: time.ANSIC}, | ||||
| 	"format_unix_date":     &objects.String{Value: time.UnixDate}, | ||||
| 	"format_ruby_date":     &objects.String{Value: time.RubyDate}, | ||||
| 	"format_rfc822":        &objects.String{Value: time.RFC822}, | ||||
| 	"format_rfc822z":       &objects.String{Value: time.RFC822Z}, | ||||
| 	"format_rfc850":        &objects.String{Value: time.RFC850}, | ||||
| 	"format_rfc1123":       &objects.String{Value: time.RFC1123}, | ||||
| 	"format_rfc1123z":      &objects.String{Value: time.RFC1123Z}, | ||||
| 	"format_rfc3339":       &objects.String{Value: time.RFC3339}, | ||||
| 	"format_rfc3339_nano":  &objects.String{Value: time.RFC3339Nano}, | ||||
| 	"format_kitchen":       &objects.String{Value: time.Kitchen}, | ||||
| 	"format_stamp":         &objects.String{Value: time.Stamp}, | ||||
| 	"format_stamp_milli":   &objects.String{Value: time.StampMilli}, | ||||
| 	"format_stamp_micro":   &objects.String{Value: time.StampMicro}, | ||||
| 	"format_stamp_nano":    &objects.String{Value: time.StampNano}, | ||||
| 	"nanosecond":           &objects.Int{Value: int64(time.Nanosecond)}, | ||||
| 	"microsecond":          &objects.Int{Value: int64(time.Microsecond)}, | ||||
| 	"millisecond":          &objects.Int{Value: int64(time.Millisecond)}, | ||||
| 	"second":               &objects.Int{Value: int64(time.Second)}, | ||||
| 	"minute":               &objects.Int{Value: int64(time.Minute)}, | ||||
| 	"hour":                 &objects.Int{Value: int64(time.Hour)}, | ||||
| 	"january":              &objects.Int{Value: int64(time.January)}, | ||||
| 	"february":             &objects.Int{Value: int64(time.February)}, | ||||
| 	"march":                &objects.Int{Value: int64(time.March)}, | ||||
| 	"april":                &objects.Int{Value: int64(time.April)}, | ||||
| 	"may":                  &objects.Int{Value: int64(time.May)}, | ||||
| 	"june":                 &objects.Int{Value: int64(time.June)}, | ||||
| 	"july":                 &objects.Int{Value: int64(time.July)}, | ||||
| 	"august":               &objects.Int{Value: int64(time.August)}, | ||||
| 	"september":            &objects.Int{Value: int64(time.September)}, | ||||
| 	"october":              &objects.Int{Value: int64(time.October)}, | ||||
| 	"november":             &objects.Int{Value: int64(time.November)}, | ||||
| 	"december":             &objects.Int{Value: int64(time.December)}, | ||||
| 	"sleep":                &objects.UserFunction{Name: "sleep", Value: timesSleep},                              // sleep(int) | ||||
| 	"parse_duration":       &objects.UserFunction{Name: "parse_duration", Value: timesParseDuration},             // parse_duration(str) => int | ||||
| 	"since":                &objects.UserFunction{Name: "since", Value: timesSince},                              // since(time) => int | ||||
| 	"until":                &objects.UserFunction{Name: "until", Value: timesUntil},                              // until(time) => int | ||||
| 	"duration_hours":       &objects.UserFunction{Name: "duration_hours", Value: timesDurationHours},             // duration_hours(int) => float | ||||
| 	"duration_minutes":     &objects.UserFunction{Name: "duration_minutes", Value: timesDurationMinutes},         // duration_minutes(int) => float | ||||
| 	"duration_nanoseconds": &objects.UserFunction{Name: "duration_nanoseconds", Value: timesDurationNanoseconds}, // duration_nanoseconds(int) => int | ||||
| 	"duration_seconds":     &objects.UserFunction{Name: "duration_seconds", Value: timesDurationSeconds},         // duration_seconds(int) => float | ||||
| 	"duration_string":      &objects.UserFunction{Name: "duration_string", Value: timesDurationString},           // duration_string(int) => string | ||||
| 	"month_string":         &objects.UserFunction{Name: "month_string", Value: timesMonthString},                 // month_string(int) => string | ||||
| 	"date":                 &objects.UserFunction{Name: "date", Value: timesDate},                                // date(year, month, day, hour, min, sec, nsec) => time | ||||
| 	"now":                  &objects.UserFunction{Name: "now", Value: timesNow},                                  // now() => time | ||||
| 	"parse":                &objects.UserFunction{Name: "parse", Value: timesParse},                              // parse(format, str) => time | ||||
| 	"unix":                 &objects.UserFunction{Name: "unix", Value: timesUnix},                                // unix(sec, nsec) => time | ||||
| 	"add":                  &objects.UserFunction{Name: "add", Value: timesAdd},                                  // add(time, int) => time | ||||
| 	"add_date":             &objects.UserFunction{Name: "add_date", Value: timesAddDate},                         // add_date(time, years, months, days) => time | ||||
| 	"sub":                  &objects.UserFunction{Name: "sub", Value: timesSub},                                  // sub(t time, u time) => int | ||||
| 	"after":                &objects.UserFunction{Name: "after", Value: timesAfter},                              // after(t time, u time) => bool | ||||
| 	"before":               &objects.UserFunction{Name: "before", Value: timesBefore},                            // before(t time, u time) => bool | ||||
| 	"time_year":            &objects.UserFunction{Name: "time_year", Value: timesTimeYear},                       // time_year(time) => int | ||||
| 	"time_month":           &objects.UserFunction{Name: "time_month", Value: timesTimeMonth},                     // time_month(time) => int | ||||
| 	"time_day":             &objects.UserFunction{Name: "time_day", Value: timesTimeDay},                         // time_day(time) => int | ||||
| 	"time_weekday":         &objects.UserFunction{Name: "time_weekday", Value: timesTimeWeekday},                 // time_weekday(time) => int | ||||
| 	"time_hour":            &objects.UserFunction{Name: "time_hour", Value: timesTimeHour},                       // time_hour(time) => int | ||||
| 	"time_minute":          &objects.UserFunction{Name: "time_minute", Value: timesTimeMinute},                   // time_minute(time) => int | ||||
| 	"time_second":          &objects.UserFunction{Name: "time_second", Value: timesTimeSecond},                   // time_second(time) => int | ||||
| 	"time_nanosecond":      &objects.UserFunction{Name: "time_nanosecond", Value: timesTimeNanosecond},           // time_nanosecond(time) => int | ||||
| 	"time_unix":            &objects.UserFunction{Name: "time_unix", Value: timesTimeUnix},                       // time_unix(time) => int | ||||
| 	"time_unix_nano":       &objects.UserFunction{Name: "time_unix_nano", Value: timesTimeUnixNano},              // time_unix_nano(time) => int | ||||
| 	"time_format":          &objects.UserFunction{Name: "time_format", Value: timesTimeFormat},                   // time_format(time, format) => string | ||||
| 	"time_location":        &objects.UserFunction{Name: "time_location", Value: timesTimeLocation},               // time_location(time) => string | ||||
| 	"time_string":          &objects.UserFunction{Name: "time_string", Value: timesTimeString},                   // time_string(time) => string | ||||
| 	"is_zero":              &objects.UserFunction{Name: "is_zero", Value: timesIsZero},                           // is_zero(time) => bool | ||||
| 	"to_local":             &objects.UserFunction{Name: "to_local", Value: timesToLocal},                         // to_local(time) => time | ||||
| 	"to_utc":               &objects.UserFunction{Name: "to_utc", Value: timesToUTC},                             // to_utc(time) => time | ||||
| } | ||||
|  | ||||
| func timesSleep(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i1, ok := objects.ToInt64(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	time.Sleep(time.Duration(i1)) | ||||
| 	ret = objects.UndefinedValue | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesParseDuration(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	dur, err := time.ParseDuration(s1) | ||||
| 	if err != nil { | ||||
| 		ret = wrapError(err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(dur)} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesSince(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(time.Since(t1))} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesUntil(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(time.Until(t1))} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesDurationHours(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i1, ok := objects.ToInt64(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Float{Value: time.Duration(i1).Hours()} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesDurationMinutes(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i1, ok := objects.ToInt64(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Float{Value: time.Duration(i1).Minutes()} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesDurationNanoseconds(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i1, ok := objects.ToInt64(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: time.Duration(i1).Nanoseconds()} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesDurationSeconds(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i1, ok := objects.ToInt64(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Float{Value: time.Duration(i1).Seconds()} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesDurationString(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i1, ok := objects.ToInt64(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.String{Value: time.Duration(i1).String()} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesMonthString(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i1, ok := objects.ToInt64(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.String{Value: time.Month(i1).String()} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesDate(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 7 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i1, ok := objects.ToInt(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	i2, ok := objects.ToInt(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	i3, ok := objects.ToInt(args[2]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "third", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[2].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	i4, ok := objects.ToInt(args[3]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "fourth", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[3].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	i5, ok := objects.ToInt(args[4]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "fifth", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[4].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	i6, ok := objects.ToInt(args[5]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "sixth", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[5].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	i7, ok := objects.ToInt(args[6]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "seventh", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[6].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Time{Value: time.Date(i1, time.Month(i2), i3, i4, i5, i6, i7, time.Now().Location())} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesNow(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 0 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Time{Value: time.Now()} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesParse(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 2 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s1, ok := objects.ToString(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s2, ok := objects.ToString(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	parsed, err := time.Parse(s1, s2) | ||||
| 	if err != nil { | ||||
| 		ret = wrapError(err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Time{Value: parsed} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesUnix(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 2 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i1, ok := objects.ToInt64(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i2, ok := objects.ToInt64(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Time{Value: time.Unix(i1, i2)} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesAdd(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 2 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i2, ok := objects.ToInt64(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Time{Value: t1.Add(time.Duration(i2))} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesSub(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 2 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t2, ok := objects.ToTime(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(t1.Sub(t2))} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesAddDate(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 4 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i2, ok := objects.ToInt(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i3, ok := objects.ToInt(args[2]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "third", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[2].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	i4, ok := objects.ToInt(args[3]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "fourth", | ||||
| 			Expected: "int(compatible)", | ||||
| 			Found:    args[3].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Time{Value: t1.AddDate(i2, i3, i4)} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesAfter(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 2 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t2, ok := objects.ToTime(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if t1.After(t2) { | ||||
| 		ret = objects.TrueValue | ||||
| 	} else { | ||||
| 		ret = objects.FalseValue | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesBefore(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 2 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t2, ok := objects.ToTime(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if t1.Before(t2) { | ||||
| 		ret = objects.TrueValue | ||||
| 	} else { | ||||
| 		ret = objects.FalseValue | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeYear(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(t1.Year())} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeMonth(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(t1.Month())} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeDay(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(t1.Day())} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeWeekday(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(t1.Weekday())} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeHour(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(t1.Hour())} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeMinute(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(t1.Minute())} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeSecond(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(t1.Second())} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeNanosecond(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(t1.Nanosecond())} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeUnix(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(t1.Unix())} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeUnixNano(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Int{Value: int64(t1.UnixNano())} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeFormat(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 2 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	s2, ok := objects.ToString(args[1]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "second", | ||||
| 			Expected: "string(compatible)", | ||||
| 			Found:    args[1].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.String{Value: t1.Format(s2)} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesIsZero(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if t1.IsZero() { | ||||
| 		ret = objects.TrueValue | ||||
| 	} else { | ||||
| 		ret = objects.FalseValue | ||||
| 	} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesToLocal(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Time{Value: t1.Local()} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesToUTC(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.Time{Value: t1.UTC()} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeLocation(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.String{Value: t1.Location().String()} | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func timesTimeString(args ...objects.Object) (ret objects.Object, err error) { | ||||
| 	if len(args) != 1 { | ||||
| 		err = objects.ErrWrongNumArguments | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	t1, ok := objects.ToTime(args[0]) | ||||
| 	if !ok { | ||||
| 		err = objects.ErrInvalidArgumentType{ | ||||
| 			Name:     "first", | ||||
| 			Expected: "time(compatible)", | ||||
| 			Found:    args[0].TypeName(), | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ret = &objects.String{Value: t1.String()} | ||||
|  | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										11
									
								
								vendor/github.com/d5/tengo/tengo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/d5/tengo/tengo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| package tengo | ||||
|  | ||||
| var ( | ||||
| 	// MaxStringLen is the maximum byte-length for string value. | ||||
| 	// Note this limit applies to all compiler/VM instances in the process. | ||||
| 	MaxStringLen = 2147483647 | ||||
|  | ||||
| 	// MaxBytesLen is the maximum length for bytes value. | ||||
| 	// Note this limit applies to all compiler/VM instances in the process. | ||||
| 	MaxBytesLen = 2147483647 | ||||
| ) | ||||
| @@ -2,7 +2,7 @@ package binary | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/Rhymen/go-whatsapp/binary/token" | ||||
| 	"github.com/matterbridge/go-whatsapp/binary/token" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| ) | ||||
| @@ -2,7 +2,7 @@ package binary | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/Rhymen/go-whatsapp/binary/token" | ||||
| 	"github.com/matterbridge/go-whatsapp/binary/token" | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| @@ -2,7 +2,7 @@ package binary | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	pb "github.com/Rhymen/go-whatsapp/binary/proto" | ||||
| 	pb "github.com/matterbridge/go-whatsapp/binary/proto" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| ) | ||||
| 
 | ||||
| @@ -14,9 +14,9 @@ import ( | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/Rhymen/go-whatsapp/binary" | ||||
| 	"github.com/Rhymen/go-whatsapp/crypto/cbc" | ||||
| 	"github.com/gorilla/websocket" | ||||
| 	"github.com/matterbridge/go-whatsapp/binary" | ||||
| 	"github.com/matterbridge/go-whatsapp/crypto/cbc" | ||||
| ) | ||||
| 
 | ||||
| type metric byte | ||||
| @@ -128,7 +128,7 @@ func NewConn(timeout time.Duration) (*Conn, error) { | ||||
| 
 | ||||
| 	go wac.readPump() | ||||
| 	go wac.writePump() | ||||
| 	go wac.keepAlive(20000, 90000) | ||||
| 	go wac.keepAlive(20000, 60000) | ||||
| 
 | ||||
| 	return wac, nil | ||||
| } | ||||
| @@ -2,7 +2,7 @@ package whatsapp | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/Rhymen/go-whatsapp/binary" | ||||
| 	"github.com/matterbridge/go-whatsapp/binary" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
| ) | ||||
| @@ -13,8 +13,8 @@ const ( | ||||
| 	PresenceAvailable   = "available" | ||||
| 	PresenceUnavailable = "unavailable" | ||||
| 	PresenceComposing   = "composing" | ||||
| 	PresenceRecording	= "recording" | ||||
| 	PresencePaused	= "paused" | ||||
| 	PresenceRecording   = "recording" | ||||
| 	PresencePaused      = "paused" | ||||
| ) | ||||
| 
 | ||||
| //TODO: filename? WhatsApp uses Store.Contacts for these functions | ||||
| @@ -30,44 +30,11 @@ func (wac *Conn) GetStatus(jid string) (<-chan string, error) { | ||||
| 	return wac.write(data) | ||||
| } | ||||
| 
 | ||||
| func (wac *Conn) GetGroupMetaData(jid string) (<-chan string, error) { | ||||
| 	data := []interface{}{"query", "GroupMetadata", jid} | ||||
| 	return wac.write(data) | ||||
| } | ||||
| 
 | ||||
| func (wac *Conn) SubscribePresence(jid string) (<-chan string, error) { | ||||
| 	data := []interface{}{"action", "presence", "subscribe", jid} | ||||
| 	return wac.write(data) | ||||
| } | ||||
| 
 | ||||
| func (wac *Conn) CreateGroup(subject string, participants []string) (<-chan string, error) { | ||||
| 	return wac.setGroup("create", "", subject, participants) | ||||
| } | ||||
| 
 | ||||
| func (wac *Conn) UpdateGroupSubject(subject string, jid string) (<-chan string, error) { | ||||
| 	return wac.setGroup("subject", jid, subject, nil) | ||||
| } | ||||
| 
 | ||||
| func (wac *Conn) SetAdmin(jid string, participants []string) (<-chan string, error) { | ||||
| 	return wac.setGroup("promote", jid, "", participants) | ||||
| } | ||||
| 
 | ||||
| func (wac *Conn) RemoveAdmin(jid string, participants []string) (<-chan string, error) { | ||||
| 	return wac.setGroup("demote", jid, "", participants) | ||||
| } | ||||
| 
 | ||||
| func (wac *Conn) AddMember(jid string, participants []string) (<-chan string, error) { | ||||
| 	return wac.setGroup("add", jid, "", participants) | ||||
| } | ||||
| 
 | ||||
| func (wac *Conn) RemoveMember(jid string, participants []string) (<-chan string, error) { | ||||
| 	return wac.setGroup("remove", jid, "", participants) | ||||
| } | ||||
| 
 | ||||
| func (wac *Conn) LeaveGroup(jid string) (<-chan string, error) { | ||||
| 	return wac.setGroup("leave", jid, "", nil) | ||||
| } | ||||
| 
 | ||||
| func (wac *Conn) Search(search string, count, page int) (*binary.Node, error) { | ||||
| 	return wac.query("search", "", "", "", "", search, count, page) | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| module github.com/Rhymen/go-whatsapp | ||||
| module github.com/matterbridge/go-whatsapp | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/golang/protobuf v1.2.0 | ||||
| @@ -1,4 +1,7 @@ | ||||
| github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= | ||||
| github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||||
| github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= | ||||
| github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= | ||||
| golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613 h1:MQ/ZZiDsUapFFiMS+vzwXkCTeEKaum+Do5rINYJDmxc= | ||||
| golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= | ||||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
							
								
								
									
										65
									
								
								vendor/github.com/matterbridge/go-whatsapp/group.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/matterbridge/go-whatsapp/group.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| package whatsapp | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func (wac *Conn) GetGroupMetaData(jid string) (<-chan string, error) { | ||||
| 	data := []interface{}{"query", "GroupMetadata", jid} | ||||
| 	return wac.write(data) | ||||
| } | ||||
|  | ||||
| func (wac *Conn) CreateGroup(subject string, participants []string) (<-chan string, error) { | ||||
| 	return wac.setGroup("create", "", subject, participants) | ||||
| } | ||||
|  | ||||
| func (wac *Conn) UpdateGroupSubject(subject string, jid string) (<-chan string, error) { | ||||
| 	return wac.setGroup("subject", jid, subject, nil) | ||||
| } | ||||
|  | ||||
| func (wac *Conn) SetAdmin(jid string, participants []string) (<-chan string, error) { | ||||
| 	return wac.setGroup("promote", jid, "", participants) | ||||
| } | ||||
|  | ||||
| func (wac *Conn) RemoveAdmin(jid string, participants []string) (<-chan string, error) { | ||||
| 	return wac.setGroup("demote", jid, "", participants) | ||||
| } | ||||
|  | ||||
| func (wac *Conn) AddMember(jid string, participants []string) (<-chan string, error) { | ||||
| 	return wac.setGroup("add", jid, "", participants) | ||||
| } | ||||
|  | ||||
| func (wac *Conn) RemoveMember(jid string, participants []string) (<-chan string, error) { | ||||
| 	return wac.setGroup("remove", jid, "", participants) | ||||
| } | ||||
|  | ||||
| func (wac *Conn) LeaveGroup(jid string) (<-chan string, error) { | ||||
| 	return wac.setGroup("leave", jid, "", nil) | ||||
| } | ||||
|  | ||||
| func (wac *Conn) GroupInviteLink(jid string) (string, error) { | ||||
| 	request := []interface{}{"query", "inviteCode", jid} | ||||
| 	ch, err := wac.write(request) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	var response map[string]interface{} | ||||
|  | ||||
| 	select { | ||||
| 	case r := <-ch: | ||||
| 		if err := json.Unmarshal([]byte(r), &response); err != nil { | ||||
| 			return "", fmt.Errorf("error decoding response message: %v\n", err) | ||||
| 		} | ||||
| 	case <-time.After(wac.msgTimeout): | ||||
| 		return "", fmt.Errorf("request timed out") | ||||
| 	} | ||||
|  | ||||
| 	if int(response["status"].(float64)) != 200 { | ||||
| 		return "", fmt.Errorf("request responded with %d", response["status"]) | ||||
| 	} | ||||
|  | ||||
| 	return response["code"].(string), nil | ||||
| } | ||||
| @@ -2,8 +2,8 @@ package whatsapp | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"github.com/Rhymen/go-whatsapp/binary" | ||||
| 	"github.com/Rhymen/go-whatsapp/binary/proto" | ||||
| 	"github.com/matterbridge/go-whatsapp/binary" | ||||
| 	"github.com/matterbridge/go-whatsapp/binary/proto" | ||||
| 	"os" | ||||
| ) | ||||
| 
 | ||||
| @@ -8,8 +8,8 @@ import ( | ||||
| 	"encoding/base64" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"github.com/Rhymen/go-whatsapp/crypto/cbc" | ||||
| 	"github.com/Rhymen/go-whatsapp/crypto/hkdf" | ||||
| 	"github.com/matterbridge/go-whatsapp/crypto/cbc" | ||||
| 	"github.com/matterbridge/go-whatsapp/crypto/hkdf" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"mime/multipart" | ||||
| @@ -4,8 +4,8 @@ import ( | ||||
| 	"encoding/hex" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"github.com/Rhymen/go-whatsapp/binary" | ||||
| 	"github.com/Rhymen/go-whatsapp/binary/proto" | ||||
| 	"github.com/matterbridge/go-whatsapp/binary" | ||||
| 	"github.com/matterbridge/go-whatsapp/binary/proto" | ||||
| 	"io" | ||||
| 	"math/rand" | ||||
| 	"strconv" | ||||
| @@ -363,6 +363,7 @@ type DocumentMessage struct { | ||||
| 	Title         string | ||||
| 	PageCount     uint32 | ||||
| 	Type          string | ||||
| 	FileName      string | ||||
| 	Thumbnail     []byte | ||||
| 	Content       io.Reader | ||||
| 	url           string | ||||
| @@ -376,15 +377,16 @@ func getDocumentMessage(msg *proto.WebMessageInfo) DocumentMessage { | ||||
| 	doc := msg.GetMessage().GetDocumentMessage() | ||||
| 	return DocumentMessage{ | ||||
| 		Info:          getMessageInfo(msg), | ||||
| 		Title:         doc.GetTitle(), | ||||
| 		PageCount:     doc.GetPageCount(), | ||||
| 		Type:          doc.GetMimetype(), | ||||
| 		FileName:      doc.GetFileName(), | ||||
| 		Thumbnail:     doc.GetJpegThumbnail(), | ||||
| 		url:           doc.GetUrl(), | ||||
| 		mediaKey:      doc.GetMediaKey(), | ||||
| 		fileEncSha256: doc.GetFileEncSha256(), | ||||
| 		fileSha256:    doc.GetFileSha256(), | ||||
| 		fileLength:    doc.GetFileLength(), | ||||
| 		PageCount:     doc.GetPageCount(), | ||||
| 		Title:         doc.GetTitle(), | ||||
| 		Type:          doc.GetMimetype(), | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @@ -9,9 +9,9 @@ import ( | ||||
| 	"fmt" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/Rhymen/go-whatsapp/crypto/cbc" | ||||
| 	"github.com/Rhymen/go-whatsapp/crypto/curve25519" | ||||
| 	"github.com/Rhymen/go-whatsapp/crypto/hkdf" | ||||
| 	"github.com/matterbridge/go-whatsapp/crypto/cbc" | ||||
| 	"github.com/matterbridge/go-whatsapp/crypto/curve25519" | ||||
| 	"github.com/matterbridge/go-whatsapp/crypto/hkdf" | ||||
| ) | ||||
| 
 | ||||
| /* | ||||
| @@ -1,7 +1,7 @@ | ||||
| package whatsapp | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/Rhymen/go-whatsapp/binary" | ||||
| 	"github.com/matterbridge/go-whatsapp/binary" | ||||
| 	"strings" | ||||
| ) | ||||
| 
 | ||||
| @@ -20,7 +20,7 @@ import ( | ||||
| 	"encoding/json" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/matterbridge/go-whatsapp" | ||||
| ) | ||||
| 
 | ||||
| type ChatUpdateCommand string | ||||
| @@ -20,7 +20,7 @@ import ( | ||||
| 	"encoding/json" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/matterbridge/go-whatsapp" | ||||
| ) | ||||
| 
 | ||||
| type CommandType string | ||||
| @@ -19,7 +19,7 @@ package whatsappExt | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 
 | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/matterbridge/go-whatsapp" | ||||
| ) | ||||
| 
 | ||||
| type ConnInfo struct { | ||||
| @@ -19,7 +19,7 @@ package whatsappExt | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 
 | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/matterbridge/go-whatsapp" | ||||
| ) | ||||
| 
 | ||||
| type JSONMessage []json.RawMessage | ||||
| @@ -20,7 +20,7 @@ import ( | ||||
| 	"encoding/json" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/matterbridge/go-whatsapp" | ||||
| ) | ||||
| 
 | ||||
| type MsgInfoCommand string | ||||
| @@ -20,7 +20,7 @@ import ( | ||||
| 	"encoding/json" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/matterbridge/go-whatsapp" | ||||
| ) | ||||
| 
 | ||||
| type PresenceType string | ||||
| @@ -19,7 +19,7 @@ package whatsappExt | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 
 | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/matterbridge/go-whatsapp" | ||||
| ) | ||||
| 
 | ||||
| type ProtocolProps struct { | ||||
| @@ -19,7 +19,7 @@ package whatsappExt | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 
 | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/matterbridge/go-whatsapp" | ||||
| ) | ||||
| 
 | ||||
| type StreamType string | ||||
| @@ -24,7 +24,7 @@ import ( | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/Rhymen/go-whatsapp" | ||||
| 	"github.com/matterbridge/go-whatsapp" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
							
								
								
									
										214
									
								
								vendor/github.com/mattn/go-colorable/colorable_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										214
									
								
								vendor/github.com/mattn/go-colorable/colorable_windows.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -29,6 +29,15 @@ const ( | ||||
| 	backgroundMask      = (backgroundRed | backgroundBlue | backgroundGreen | backgroundIntensity) | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	genericRead  = 0x80000000 | ||||
| 	genericWrite = 0x40000000 | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	consoleTextmodeBuffer = 0x1 | ||||
| ) | ||||
|  | ||||
| type wchar uint16 | ||||
| type short int16 | ||||
| type dword uint32 | ||||
| @@ -69,14 +78,17 @@ var ( | ||||
| 	procGetConsoleCursorInfo       = kernel32.NewProc("GetConsoleCursorInfo") | ||||
| 	procSetConsoleCursorInfo       = kernel32.NewProc("SetConsoleCursorInfo") | ||||
| 	procSetConsoleTitle            = kernel32.NewProc("SetConsoleTitleW") | ||||
| 	procCreateConsoleScreenBuffer  = kernel32.NewProc("CreateConsoleScreenBuffer") | ||||
| ) | ||||
|  | ||||
| // Writer provide colorable Writer to the console | ||||
| type Writer struct { | ||||
| 	out     io.Writer | ||||
| 	handle  syscall.Handle | ||||
| 	oldattr word | ||||
| 	oldpos  coord | ||||
| 	out       io.Writer | ||||
| 	handle    syscall.Handle | ||||
| 	althandle syscall.Handle | ||||
| 	oldattr   word | ||||
| 	oldpos    coord | ||||
| 	rest      bytes.Buffer | ||||
| } | ||||
|  | ||||
| // NewColorable return new instance of Writer which handle escape sequence from File. | ||||
| @@ -407,7 +419,18 @@ func (w *Writer) Write(data []byte) (n int, err error) { | ||||
| 	var csbi consoleScreenBufferInfo | ||||
| 	procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
|  | ||||
| 	er := bytes.NewReader(data) | ||||
| 	handle := w.handle | ||||
|  | ||||
| 	var er *bytes.Reader | ||||
| 	if w.rest.Len() > 0 { | ||||
| 		var rest bytes.Buffer | ||||
| 		w.rest.WriteTo(&rest) | ||||
| 		w.rest.Reset() | ||||
| 		rest.Write(data) | ||||
| 		er = bytes.NewReader(rest.Bytes()) | ||||
| 	} else { | ||||
| 		er = bytes.NewReader(data) | ||||
| 	} | ||||
| 	var bw [1]byte | ||||
| loop: | ||||
| 	for { | ||||
| @@ -425,29 +448,55 @@ loop: | ||||
| 			break loop | ||||
| 		} | ||||
|  | ||||
| 		if c2 == ']' { | ||||
| 			if err := doTitleSequence(er); err != nil { | ||||
| 		switch c2 { | ||||
| 		case '>': | ||||
| 			continue | ||||
| 		case ']': | ||||
| 			w.rest.WriteByte(c1) | ||||
| 			w.rest.WriteByte(c2) | ||||
| 			er.WriteTo(&w.rest) | ||||
| 			if bytes.IndexByte(w.rest.Bytes(), 0x07) == -1 { | ||||
| 				break loop | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		if c2 != 0x5b { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		var buf bytes.Buffer | ||||
| 		var m byte | ||||
| 		for { | ||||
| 			c, err := er.ReadByte() | ||||
| 			er = bytes.NewReader(w.rest.Bytes()[2:]) | ||||
| 			err := doTitleSequence(er) | ||||
| 			if err != nil { | ||||
| 				break loop | ||||
| 			} | ||||
| 			w.rest.Reset() | ||||
| 			continue | ||||
| 		// https://github.com/mattn/go-colorable/issues/27 | ||||
| 		case '7': | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			w.oldpos = csbi.cursorPosition | ||||
| 			continue | ||||
| 		case '8': | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) | ||||
| 			continue | ||||
| 		case 0x5b: | ||||
| 			// execute part after switch | ||||
| 		default: | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		w.rest.WriteByte(c1) | ||||
| 		w.rest.WriteByte(c2) | ||||
| 		er.WriteTo(&w.rest) | ||||
|  | ||||
| 		var buf bytes.Buffer | ||||
| 		var m byte | ||||
| 		for i, c := range w.rest.Bytes()[2:] { | ||||
| 			if ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '@' { | ||||
| 				m = c | ||||
| 				er = bytes.NewReader(w.rest.Bytes()[2+i+1:]) | ||||
| 				w.rest.Reset() | ||||
| 				break | ||||
| 			} | ||||
| 			buf.Write([]byte(string(c))) | ||||
| 		} | ||||
| 		if m == 0 { | ||||
| 			break loop | ||||
| 		} | ||||
|  | ||||
| 		switch m { | ||||
| 		case 'A': | ||||
| @@ -455,61 +504,64 @@ loop: | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			csbi.cursorPosition.y -= short(n) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 		case 'B': | ||||
| 			n, err = strconv.Atoi(buf.String()) | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			csbi.cursorPosition.y += short(n) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 		case 'C': | ||||
| 			n, err = strconv.Atoi(buf.String()) | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			csbi.cursorPosition.x += short(n) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 		case 'D': | ||||
| 			n, err = strconv.Atoi(buf.String()) | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			csbi.cursorPosition.x -= short(n) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 			if csbi.cursorPosition.x < 0 { | ||||
| 				csbi.cursorPosition.x = 0 | ||||
| 			} | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 		case 'E': | ||||
| 			n, err = strconv.Atoi(buf.String()) | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			csbi.cursorPosition.x = 0 | ||||
| 			csbi.cursorPosition.y += short(n) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 		case 'F': | ||||
| 			n, err = strconv.Atoi(buf.String()) | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			csbi.cursorPosition.x = 0 | ||||
| 			csbi.cursorPosition.y -= short(n) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 		case 'G': | ||||
| 			n, err = strconv.Atoi(buf.String()) | ||||
| 			if err != nil { | ||||
| 				continue | ||||
| 			} | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			csbi.cursorPosition.x = short(n - 1) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 		case 'H', 'f': | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			if buf.Len() > 0 { | ||||
| 				token := strings.Split(buf.String(), ";") | ||||
| 				switch len(token) { | ||||
| @@ -534,7 +586,7 @@ loop: | ||||
| 			} else { | ||||
| 				csbi.cursorPosition.y = 0 | ||||
| 			} | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&csbi.cursorPosition))) | ||||
| 		case 'J': | ||||
| 			n := 0 | ||||
| 			if buf.Len() > 0 { | ||||
| @@ -545,20 +597,20 @@ loop: | ||||
| 			} | ||||
| 			var count, written dword | ||||
| 			var cursor coord | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			switch n { | ||||
| 			case 0: | ||||
| 				cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} | ||||
| 				count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) | ||||
| 				count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x) | ||||
| 			case 1: | ||||
| 				cursor = coord{x: csbi.window.left, y: csbi.window.top} | ||||
| 				count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.window.top-csbi.cursorPosition.y)*csbi.size.x) | ||||
| 				count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.window.top-csbi.cursorPosition.y)*dword(csbi.size.x) | ||||
| 			case 2: | ||||
| 				cursor = coord{x: csbi.window.left, y: csbi.window.top} | ||||
| 				count = dword(csbi.size.x - csbi.cursorPosition.x + (csbi.size.y-csbi.cursorPosition.y)*csbi.size.x) | ||||
| 				count = dword(csbi.size.x) - dword(csbi.cursorPosition.x) + dword(csbi.size.y-csbi.cursorPosition.y)*dword(csbi.size.x) | ||||
| 			} | ||||
| 			procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) | ||||
| 			procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) | ||||
| 			procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) | ||||
| 			procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) | ||||
| 		case 'K': | ||||
| 			n := 0 | ||||
| 			if buf.Len() > 0 { | ||||
| @@ -567,28 +619,28 @@ loop: | ||||
| 					continue | ||||
| 				} | ||||
| 			} | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			var cursor coord | ||||
| 			var count, written dword | ||||
| 			switch n { | ||||
| 			case 0: | ||||
| 				cursor = coord{x: csbi.cursorPosition.x + 1, y: csbi.cursorPosition.y} | ||||
| 				count = dword(csbi.size.x - csbi.cursorPosition.x - 1) | ||||
| 				cursor = coord{x: csbi.cursorPosition.x, y: csbi.cursorPosition.y} | ||||
| 				count = dword(csbi.size.x - csbi.cursorPosition.x) | ||||
| 			case 1: | ||||
| 				cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} | ||||
| 				cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y} | ||||
| 				count = dword(csbi.size.x - csbi.cursorPosition.x) | ||||
| 			case 2: | ||||
| 				cursor = coord{x: csbi.window.left, y: csbi.window.top + csbi.cursorPosition.y} | ||||
| 				cursor = coord{x: csbi.window.left, y: csbi.cursorPosition.y} | ||||
| 				count = dword(csbi.size.x) | ||||
| 			} | ||||
| 			procFillConsoleOutputCharacter.Call(uintptr(w.handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) | ||||
| 			procFillConsoleOutputAttribute.Call(uintptr(w.handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) | ||||
| 			procFillConsoleOutputCharacter.Call(uintptr(handle), uintptr(' '), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) | ||||
| 			procFillConsoleOutputAttribute.Call(uintptr(handle), uintptr(csbi.attributes), uintptr(count), *(*uintptr)(unsafe.Pointer(&cursor)), uintptr(unsafe.Pointer(&written))) | ||||
| 		case 'm': | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			attr := csbi.attributes | ||||
| 			cs := buf.String() | ||||
| 			if cs == "" { | ||||
| 				procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(w.oldattr)) | ||||
| 				procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(w.oldattr)) | ||||
| 				continue | ||||
| 			} | ||||
| 			token := strings.Split(cs, ";") | ||||
| @@ -627,6 +679,21 @@ loop: | ||||
| 								attr |= n256foreAttr[n256] | ||||
| 								i += 2 | ||||
| 							} | ||||
| 						} else if len(token) == 5 && token[i+1] == "2" { | ||||
| 							var r, g, b int | ||||
| 							r, _ = strconv.Atoi(token[i+2]) | ||||
| 							g, _ = strconv.Atoi(token[i+3]) | ||||
| 							b, _ = strconv.Atoi(token[i+4]) | ||||
| 							i += 4 | ||||
| 							if r > 127 { | ||||
| 								attr |= foregroundRed | ||||
| 							} | ||||
| 							if g > 127 { | ||||
| 								attr |= foregroundGreen | ||||
| 							} | ||||
| 							if b > 127 { | ||||
| 								attr |= foregroundBlue | ||||
| 							} | ||||
| 						} else { | ||||
| 							attr = attr & (w.oldattr & backgroundMask) | ||||
| 						} | ||||
| @@ -654,6 +721,21 @@ loop: | ||||
| 								attr |= n256backAttr[n256] | ||||
| 								i += 2 | ||||
| 							} | ||||
| 						} else if len(token) == 5 && token[i+1] == "2" { | ||||
| 							var r, g, b int | ||||
| 							r, _ = strconv.Atoi(token[i+2]) | ||||
| 							g, _ = strconv.Atoi(token[i+3]) | ||||
| 							b, _ = strconv.Atoi(token[i+4]) | ||||
| 							i += 4 | ||||
| 							if r > 127 { | ||||
| 								attr |= backgroundRed | ||||
| 							} | ||||
| 							if g > 127 { | ||||
| 								attr |= backgroundGreen | ||||
| 							} | ||||
| 							if b > 127 { | ||||
| 								attr |= backgroundBlue | ||||
| 							} | ||||
| 						} else { | ||||
| 							attr = attr & (w.oldattr & foregroundMask) | ||||
| 						} | ||||
| @@ -685,38 +767,52 @@ loop: | ||||
| 							attr |= backgroundBlue | ||||
| 						} | ||||
| 					} | ||||
| 					procSetConsoleTextAttribute.Call(uintptr(w.handle), uintptr(attr)) | ||||
| 					procSetConsoleTextAttribute.Call(uintptr(handle), uintptr(attr)) | ||||
| 				} | ||||
| 			} | ||||
| 		case 'h': | ||||
| 			var ci consoleCursorInfo | ||||
| 			cs := buf.String() | ||||
| 			if cs == "5>" { | ||||
| 				procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 				procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 				ci.visible = 0 | ||||
| 				procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 				procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 			} else if cs == "?25" { | ||||
| 				procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 				procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 				ci.visible = 1 | ||||
| 				procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 				procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 			} else if cs == "?1049" { | ||||
| 				if w.althandle == 0 { | ||||
| 					h, _, _ := procCreateConsoleScreenBuffer.Call(uintptr(genericRead|genericWrite), 0, 0, uintptr(consoleTextmodeBuffer), 0, 0) | ||||
| 					w.althandle = syscall.Handle(h) | ||||
| 					if w.althandle != 0 { | ||||
| 						handle = w.althandle | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		case 'l': | ||||
| 			var ci consoleCursorInfo | ||||
| 			cs := buf.String() | ||||
| 			if cs == "5>" { | ||||
| 				procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 				procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 				ci.visible = 1 | ||||
| 				procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 				procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 			} else if cs == "?25" { | ||||
| 				procGetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 				procGetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 				ci.visible = 0 | ||||
| 				procSetConsoleCursorInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 				procSetConsoleCursorInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&ci))) | ||||
| 			} else if cs == "?1049" { | ||||
| 				if w.althandle != 0 { | ||||
| 					syscall.CloseHandle(w.althandle) | ||||
| 					w.althandle = 0 | ||||
| 					handle = w.handle | ||||
| 				} | ||||
| 			} | ||||
| 		case 's': | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(w.handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			procGetConsoleScreenBufferInfo.Call(uintptr(handle), uintptr(unsafe.Pointer(&csbi))) | ||||
| 			w.oldpos = csbi.cursorPosition | ||||
| 		case 'u': | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(w.handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) | ||||
| 			procSetConsoleCursorPosition.Call(uintptr(handle), *(*uintptr)(unsafe.Pointer(&w.oldpos))) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/mattn/go-colorable/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/mattn/go-colorable/go.mod
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| module github.com/mattn/go-colorable | ||||
|  | ||||
| require github.com/mattn/go-isatty v0.0.5 | ||||
							
								
								
									
										4
									
								
								vendor/github.com/mattn/go-colorable/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/mattn/go-colorable/go.sum
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| github.com/mattn/go-isatty v0.0.5 h1:tHXDdz1cpzGaovsTB+TVB8q90WEokoVmfMqoVcrLUgw= | ||||
| github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= | ||||
| golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8= | ||||
| golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user